Skip to content

Commit 3336ddf

Browse files
authored
Merge pull request #48 from bonroyage/collection-validation
Support validation for CollectionType with fields
2 parents 24708b5 + b47cc9d commit 3336ddf

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

src/Extension/Validation/ValidationListener.php

+13
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ protected function findRules(FormInterface $parent, $rules = [], $parentName = n
9797
if ($innerType instanceof CollectionType) {
9898
$children = $form->all();
9999
if (isset($children[0])) {
100+
$config = $children[0]->getConfig();
101+
$innerType = $children[0]->getConfig()->getType()->getInnerType();
102+
103+
if ($config->hasOption('rules')) {
104+
$rules[$name . '.*'] = $this->addTypeRules($innerType, $config->getOption('rules'));
105+
}
106+
100107
$rules = $this->findRules($children[0], $rules, $name . '.*');
101108
}
102109
}
@@ -150,6 +157,12 @@ protected function addTypeRules(FormTypeInterface $type, array $rules)
150157
$rules[] = 'string';
151158
}
152159

160+
if (($type instanceof CollectionType)
161+
&& !in_array('array', $rules)
162+
) {
163+
$rules[] = 'array';
164+
}
165+
153166
return $rules;
154167
}
155168
}

tests/Types/ParentFormType.php

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Symfony\Component\Form\AbstractType;
55
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
6+
use Symfony\Component\Form\Extension\Core\Type\EmailType;
67
use Symfony\Component\Form\Extension\Core\Type\TextType;
78
use Symfony\Component\Form\FormBuilderInterface;
89

@@ -18,6 +19,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
1819
'entry_type' => UserFormType::class,
1920
'allow_add' => true,
2021
])
22+
->add('emails', CollectionType::class, [
23+
'entry_type' => EmailType::class,
24+
'allow_add' => true,
25+
'rules' => ['min:1'],
26+
'entry_options' => [
27+
'rules' => ['distinct'],
28+
],
29+
])
2130
;
2231
}
2332
}

tests/ValidationTest.php

+89-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<?php
22
namespace Barryvdh\Form\Tests;
33

4+
use Barryvdh\Form\Extension\Validation\ValidationListener;
45
use Barryvdh\Form\Facade\FormFactory;
56
use Barryvdh\Form\Tests\Types\ParentFormType;
67
use Barryvdh\Form\Tests\Types\UserFormType;
78
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
9+
use Symfony\Component\Form\FormInterface;
810
use Symfony\Component\HttpFoundation\Request;
911

1012
class ValidationTest extends TestCase
@@ -107,7 +109,11 @@ public function testInvalidCollectionForm()
107109
[
108110
'name' => 'Bar',
109111
'email' => 'bar',
110-
]
112+
],
113+
],
114+
'emails' => [
115+
'foo',
116+
111117
],
112118
'save' => true,
113119
]
@@ -117,7 +123,13 @@ public function testInvalidCollectionForm()
117123

118124
$this->assertTrue($form->isSubmitted());
119125
$this->assertFalse($form->isValid());
120-
$this->assertEquals('The children.1.email must be a valid email address.', $form->getErrors(true)[0]->getMessage());
126+
127+
$this->assertEqualsCanonicalizing([
128+
'The children.1.email must be a valid email address.',
129+
'The emails.0 must be a valid email address.',
130+
], array_map(function($error) {
131+
return $error->getMessage();
132+
}, iterator_to_array($form->getErrors(true))));
121133
}
122134

123135
public function testValidCollectionForm()
@@ -139,6 +151,10 @@ public function testValidCollectionForm()
139151
'email' => '[email protected]',
140152
]
141153
],
154+
'emails' => [
155+
156+
157+
],
142158
'save' => true,
143159
]
144160
]);
@@ -149,10 +165,81 @@ public function testValidCollectionForm()
149165
$this->assertTrue($form->isValid());
150166
}
151167

168+
public function testFindRules() {
169+
/** @var \Symfony\Component\Form\Form $form */
170+
$form = FormFactory::create(ParentFormType::class, []);
171+
172+
$request = $this->createPostRequest([
173+
'parent_form' => [
174+
'name' => 'Barry',
175+
'children' => [
176+
[
177+
'name' => 'Foo',
178+
'email' => '[email protected]',
179+
],
180+
[
181+
'name' => 'Bar',
182+
'email' => '[email protected]',
183+
]
184+
],
185+
'emails' => [
186+
187+
188+
],
189+
'save' => true,
190+
]
191+
]);
192+
193+
$form->handleRequest($request);
194+
195+
$validator = $this->app->make(TestValidationListener::class);
196+
$rules = $validator->publicFindRules($form);
197+
198+
$this->assertSame([
199+
'name' => [
200+
'required',
201+
'string',
202+
],
203+
'children' => [
204+
'required',
205+
'array',
206+
],
207+
'children.*' => [
208+
'required',
209+
],
210+
'children.*.name' => [
211+
'required',
212+
'string',
213+
],
214+
'children.*.email' => [
215+
'email',
216+
'required',
217+
],
218+
'emails' => [
219+
'min:1',
220+
'required',
221+
'array',
222+
],
223+
'emails.*' => [
224+
'distinct',
225+
'required',
226+
'email',
227+
],
228+
], $rules);
229+
}
230+
152231
private function createPostRequest($data)
153232
{
154233
return new Request([], $data, [], [], [], [
155234
'REQUEST_METHOD' => 'POST'
156235
]);
157236
}
158237
}
238+
239+
class TestValidationListener extends ValidationListener
240+
{
241+
public function publicFindRules(FormInterface $parent)
242+
{
243+
return $this->findRules($parent);
244+
}
245+
}

0 commit comments

Comments
 (0)