Skip to content

Commit

Permalink
Merge pull request #48 from bonroyage/collection-validation
Browse files Browse the repository at this point in the history
Support validation for CollectionType with fields
  • Loading branch information
barryvdh authored Feb 6, 2023
2 parents 24708b5 + b47cc9d commit 3336ddf
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/Extension/Validation/ValidationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ protected function findRules(FormInterface $parent, $rules = [], $parentName = n
if ($innerType instanceof CollectionType) {
$children = $form->all();
if (isset($children[0])) {
$config = $children[0]->getConfig();
$innerType = $children[0]->getConfig()->getType()->getInnerType();

if ($config->hasOption('rules')) {
$rules[$name . '.*'] = $this->addTypeRules($innerType, $config->getOption('rules'));
}

$rules = $this->findRules($children[0], $rules, $name . '.*');
}
}
Expand Down Expand Up @@ -150,6 +157,12 @@ protected function addTypeRules(FormTypeInterface $type, array $rules)
$rules[] = 'string';
}

if (($type instanceof CollectionType)
&& !in_array('array', $rules)
) {
$rules[] = 'array';
}

return $rules;
}
}
9 changes: 9 additions & 0 deletions tests/Types/ParentFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

Expand All @@ -18,6 +19,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'entry_type' => UserFormType::class,
'allow_add' => true,
])
->add('emails', CollectionType::class, [
'entry_type' => EmailType::class,
'allow_add' => true,
'rules' => ['min:1'],
'entry_options' => [
'rules' => ['distinct'],
],
])
;
}
}
91 changes: 89 additions & 2 deletions tests/ValidationTest.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php
namespace Barryvdh\Form\Tests;

use Barryvdh\Form\Extension\Validation\ValidationListener;
use Barryvdh\Form\Facade\FormFactory;
use Barryvdh\Form\Tests\Types\ParentFormType;
use Barryvdh\Form\Tests\Types\UserFormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;

class ValidationTest extends TestCase
Expand Down Expand Up @@ -107,7 +109,11 @@ public function testInvalidCollectionForm()
[
'name' => 'Bar',
'email' => 'bar',
]
],
],
'emails' => [
'foo',
'[email protected]',
],
'save' => true,
]
Expand All @@ -117,7 +123,13 @@ public function testInvalidCollectionForm()

$this->assertTrue($form->isSubmitted());
$this->assertFalse($form->isValid());
$this->assertEquals('The children.1.email must be a valid email address.', $form->getErrors(true)[0]->getMessage());

$this->assertEqualsCanonicalizing([
'The children.1.email must be a valid email address.',
'The emails.0 must be a valid email address.',
], array_map(function($error) {
return $error->getMessage();
}, iterator_to_array($form->getErrors(true))));
}

public function testValidCollectionForm()
Expand All @@ -139,6 +151,10 @@ public function testValidCollectionForm()
'email' => '[email protected]',
]
],
'emails' => [
'[email protected]',
'[email protected]',
],
'save' => true,
]
]);
Expand All @@ -149,10 +165,81 @@ public function testValidCollectionForm()
$this->assertTrue($form->isValid());
}

public function testFindRules() {
/** @var \Symfony\Component\Form\Form $form */
$form = FormFactory::create(ParentFormType::class, []);

$request = $this->createPostRequest([
'parent_form' => [
'name' => 'Barry',
'children' => [
[
'name' => 'Foo',
'email' => '[email protected]',
],
[
'name' => 'Bar',
'email' => '[email protected]',
]
],
'emails' => [
'[email protected]',
'[email protected]',
],
'save' => true,
]
]);

$form->handleRequest($request);

$validator = $this->app->make(TestValidationListener::class);
$rules = $validator->publicFindRules($form);

$this->assertSame([
'name' => [
'required',
'string',
],
'children' => [
'required',
'array',
],
'children.*' => [
'required',
],
'children.*.name' => [
'required',
'string',
],
'children.*.email' => [
'email',
'required',
],
'emails' => [
'min:1',
'required',
'array',
],
'emails.*' => [
'distinct',
'required',
'email',
],
], $rules);
}

private function createPostRequest($data)
{
return new Request([], $data, [], [], [], [
'REQUEST_METHOD' => 'POST'
]);
}
}

class TestValidationListener extends ValidationListener
{
public function publicFindRules(FormInterface $parent)
{
return $this->findRules($parent);
}
}

0 comments on commit 3336ddf

Please sign in to comment.