Skip to content

Commit a435596

Browse files
add test for CollectionType error property paths
1 parent 52a0233 commit a435596

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php

+91
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
use Symfony\Component\Form\Form;
1616
use Symfony\Component\Form\Forms;
1717
use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait;
18+
use Symfony\Component\Form\Tests\Extension\Core\Type\CollectionTypeTest;
1819
use Symfony\Component\Form\Tests\Extension\Core\Type\FormTypeTest;
1920
use Symfony\Component\Form\Tests\Extension\Core\Type\TextTypeTest;
2021
use Symfony\Component\Form\Tests\Fixtures\Author;
22+
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
23+
use Symfony\Component\Form\Tests\Fixtures\Organization;
2124
use Symfony\Component\Validator\Constraints\GroupSequence;
2225
use Symfony\Component\Validator\Constraints\Length;
2326
use Symfony\Component\Validator\Constraints\NotBlank;
@@ -141,4 +144,92 @@ protected function createForm(array $options = [])
141144
{
142145
return $this->factory->create(FormTypeTest::TESTED_TYPE, null, $options);
143146
}
147+
148+
public function testErrorPathOnCollections()
149+
{
150+
$formMetadata = new ClassMetadata(Form::class);
151+
$authorMetadata = (new ClassMetadata(Author::class))
152+
->addPropertyConstraint('firstName', new NotBlank());
153+
$organizationMetadata = (new ClassMetadata(Organization::class))
154+
->addPropertyConstraint('authors', new Valid());
155+
$metadataFactory = $this->createMock(MetadataFactoryInterface::class);
156+
$metadataFactory->expects($this->any())
157+
->method('getMetadataFor')
158+
->willReturnCallback(static function ($classOrObject) use ($formMetadata, $authorMetadata,$organizationMetadata) {
159+
if (Author::class === $classOrObject || $classOrObject instanceof Author) {
160+
return $authorMetadata;
161+
}
162+
163+
if (Organization::class === $classOrObject || $classOrObject instanceof Organization) {
164+
return $organizationMetadata;
165+
}
166+
167+
if (Form::class === $classOrObject || $classOrObject instanceof Form) {
168+
return $formMetadata;
169+
}
170+
171+
return new ClassMetadata(\is_string($classOrObject) ? $classOrObject : \get_class($classOrObject));
172+
});
173+
174+
$validator = Validation::createValidatorBuilder()
175+
->setMetadataFactory($metadataFactory)
176+
->getValidator();
177+
178+
$form = Forms::createFormFactoryBuilder()
179+
->addExtension(new ValidatorExtension($validator))
180+
->getFormFactory()
181+
->create(FormTypeTest::TESTED_TYPE, new Organization([]), [
182+
'data_class' => Organization::class,
183+
'by_reference' => false,
184+
])
185+
->add('authors', CollectionTypeTest::TESTED_TYPE, [
186+
'entry_type' => AuthorType::class,
187+
'allow_add' => true,
188+
'allow_delete' => true,
189+
])
190+
;
191+
192+
$form->submit([
193+
'authors' => [
194+
0 => [
195+
'firstName' => '', // Fires a Not Blank Error
196+
'lastName' => 'lastName1',
197+
],
198+
// key "1" could be missing if we add 4 blank form entries and then remove it.
199+
2 => [
200+
'firstName' => '', // Fires a Not Blank Error
201+
'lastName' => 'lastName3',
202+
],
203+
3 => [
204+
'firstName' => '', // Fires a Not Blank Error
205+
'lastName' => 'lastName3',
206+
],
207+
],
208+
]);
209+
210+
//Form behaves right (...?). It has index 0, 2 and 3 (1 has been removed)
211+
$this->assertTrue($form->get('authors')->has('0'));
212+
$this->assertFalse($form->get('authors')->has('1'));
213+
$this->assertTrue($form->get('authors')->has('2'));
214+
$this->assertTrue($form->get('authors')->has('3'));
215+
216+
//Form does have 3 not blank errors
217+
$errors = $form->getErrors(true);
218+
$this->assertCount(3, $errors);
219+
220+
//But errors property paths are messing up
221+
$errorPaths = [
222+
$errors[0]->getCause()->getPropertyPath(),
223+
$errors[1]->getCause()->getPropertyPath(),
224+
$errors[2]->getCause()->getPropertyPath(),
225+
];
226+
227+
$this->assertContains('data.authors[0].firstName',$errorPaths);
228+
$this->assertNotContains('data.authors[1].firstName',$errorPaths);
229+
$this->assertContains('data.authors[2].firstName',$errorPaths);
230+
$this->assertContains('data.authors[3].firstName',$errorPaths);
231+
232+
//In fact, root form should NOT contain errors but it does
233+
$this->assertCount(0, $form->getErrors(false));
234+
}
144235
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Symfony\Component\Form\Tests\Fixtures;
4+
5+
class Organization
6+
{
7+
public $authors = [];
8+
9+
public function __construct(array $authors = [])
10+
{
11+
$this->authors = $authors;
12+
}
13+
14+
public function getAuthors(): array
15+
{
16+
return $this->authors;
17+
}
18+
19+
public function addAuthor(Author $author): self
20+
{
21+
$this->authors[] = $author;
22+
return $this;
23+
}
24+
25+
public function removeAuthor(Author $author): self
26+
{
27+
if (false !== $key = array_search($author, $this->authors, true)) {
28+
array_splice($this->authors, $key, 1);
29+
}
30+
return $this;
31+
}
32+
}

0 commit comments

Comments
 (0)