19
19
use Symfony \Component \Form \Tests \Extension \Core \Type \FormTypeTest ;
20
20
use Symfony \Component \Form \Tests \Extension \Core \Type \TextTypeTest ;
21
21
use Symfony \Component \Form \Tests \Fixtures \Author ;
22
- use Symfony \Component \OptionsResolver \Exception \InvalidOptionsException ;
23
22
use Symfony \Component \Form \Tests \Fixtures \AuthorType ;
24
23
use Symfony \Component \Form \Tests \Fixtures \Organization ;
24
+ use Symfony \Component \OptionsResolver \Exception \InvalidOptionsException ;
25
25
use Symfony \Component \Validator \Constraints \GroupSequence ;
26
26
use Symfony \Component \Validator \Constraints \Length ;
27
27
use Symfony \Component \Validator \Constraints \NotBlank ;
@@ -162,7 +162,7 @@ protected function createForm(array $options = [])
162
162
return $ this ->factory ->create (FormTypeTest::TESTED_TYPE , null , $ options );
163
163
}
164
164
165
- public function testErrorPathOnCollections ()
165
+ public function testCollectionTypeKeepAsListOptionFalse ()
166
166
{
167
167
$ formMetadata = new ClassMetadata (Form::class);
168
168
$ authorMetadata = (new ClassMetadata (Author::class))
@@ -185,7 +185,7 @@ public function testErrorPathOnCollections()
185
185
return $ formMetadata ;
186
186
}
187
187
188
- return new ClassMetadata (\is_string ($ classOrObject ) ? $ classOrObject : \get_class ( $ classOrObject) );
188
+ return new ClassMetadata (\is_string ($ classOrObject ) ? $ classOrObject : $ classOrObject::class );
189
189
});
190
190
191
191
$ validator = Validation::createValidatorBuilder ()
@@ -203,6 +203,7 @@ public function testErrorPathOnCollections()
203
203
'entry_type ' => AuthorType::class,
204
204
'allow_add ' => true ,
205
205
'allow_delete ' => true ,
206
+ 'keep_as_list ' => false ,
206
207
])
207
208
;
208
209
@@ -224,29 +225,121 @@ public function testErrorPathOnCollections()
224
225
],
225
226
]);
226
227
227
- //Form behaves right (...?). It has index 0, 2 and 3 (1 has been removed)
228
+ // Form does have 3 not blank errors
229
+ $ errors = $ form ->getErrors (true );
230
+ $ this ->assertCount (3 , $ errors );
231
+
232
+ // Form behaves as expected. It has index 0, 2 and 3 (1 has been removed)
233
+ // But errors property paths mismatch happening with "keep_as_list" option set to false
234
+ $ errorPaths = [
235
+ $ errors [0 ]->getCause ()->getPropertyPath (),
236
+ $ errors [1 ]->getCause ()->getPropertyPath (),
237
+ $ errors [2 ]->getCause ()->getPropertyPath (),
238
+ ];
239
+
228
240
$ this ->assertTrue ($ form ->get ('authors ' )->has ('0 ' ));
241
+ $ this ->assertContains ('data.authors[0].firstName ' , $ errorPaths );
242
+
229
243
$ this ->assertFalse ($ form ->get ('authors ' )->has ('1 ' ));
244
+ $ this ->assertContains ('data.authors[1].firstName ' , $ errorPaths );
245
+
230
246
$ this ->assertTrue ($ form ->get ('authors ' )->has ('2 ' ));
247
+ $ this ->assertContains ('data.authors[2].firstName ' , $ errorPaths );
248
+
231
249
$ this ->assertTrue ($ form ->get ('authors ' )->has ('3 ' ));
250
+ $ this ->assertNotContains ('data.authors[3].firstName ' , $ errorPaths );
232
251
233
- //Form does have 3 not blank errors
252
+ // As result, root form contain errors
253
+ $ this ->assertCount (1 , $ form ->getErrors (false ));
254
+ }
255
+
256
+ public function testCollectionTypeKeepAsListOptionTrue ()
257
+ {
258
+ $ formMetadata = new ClassMetadata (Form::class);
259
+ $ authorMetadata = (new ClassMetadata (Author::class))
260
+ ->addPropertyConstraint ('firstName ' , new NotBlank ());
261
+ $ organizationMetadata = (new ClassMetadata (Organization::class))
262
+ ->addPropertyConstraint ('authors ' , new Valid ());
263
+ $ metadataFactory = $ this ->createMock (MetadataFactoryInterface::class);
264
+ $ metadataFactory ->expects ($ this ->any ())
265
+ ->method ('getMetadataFor ' )
266
+ ->willReturnCallback (static function ($ classOrObject ) use ($ formMetadata , $ authorMetadata , $ organizationMetadata ) {
267
+ if (Author::class === $ classOrObject || $ classOrObject instanceof Author) {
268
+ return $ authorMetadata ;
269
+ }
270
+
271
+ if (Organization::class === $ classOrObject || $ classOrObject instanceof Organization) {
272
+ return $ organizationMetadata ;
273
+ }
274
+
275
+ if (Form::class === $ classOrObject || $ classOrObject instanceof Form) {
276
+ return $ formMetadata ;
277
+ }
278
+
279
+ return new ClassMetadata (\is_string ($ classOrObject ) ? $ classOrObject : $ classOrObject ::class);
280
+ });
281
+
282
+ $ validator = Validation::createValidatorBuilder ()
283
+ ->setMetadataFactory ($ metadataFactory )
284
+ ->getValidator ();
285
+
286
+ $ form = Forms::createFormFactoryBuilder ()
287
+ ->addExtension (new ValidatorExtension ($ validator ))
288
+ ->getFormFactory ()
289
+ ->create (FormTypeTest::TESTED_TYPE , new Organization ([]), [
290
+ 'data_class ' => Organization::class,
291
+ 'by_reference ' => false ,
292
+ ])
293
+ ->add ('authors ' , CollectionTypeTest::TESTED_TYPE , [
294
+ 'entry_type ' => AuthorType::class,
295
+ 'allow_add ' => true ,
296
+ 'allow_delete ' => true ,
297
+ 'keep_as_list ' => true ,
298
+ ])
299
+ ;
300
+
301
+ $ form ->submit ([
302
+ 'authors ' => [
303
+ 0 => [
304
+ 'firstName ' => '' , // Fires a Not Blank Error
305
+ 'lastName ' => 'lastName1 ' ,
306
+ ],
307
+ // key "1" could be missing if we add 4 blank form entries and then remove it.
308
+ 2 => [
309
+ 'firstName ' => '' , // Fires a Not Blank Error
310
+ 'lastName ' => 'lastName3 ' ,
311
+ ],
312
+ 3 => [
313
+ 'firstName ' => '' , // Fires a Not Blank Error
314
+ 'lastName ' => 'lastName3 ' ,
315
+ ],
316
+ ],
317
+ ]);
318
+
319
+ // Form does have 3 not blank errors
234
320
$ errors = $ form ->getErrors (true );
235
321
$ this ->assertCount (3 , $ errors );
236
322
237
- //But errors property paths are messing up
323
+ // No property paths mismatch happening with "keep_as_list" option set to true
238
324
$ errorPaths = [
239
325
$ errors [0 ]->getCause ()->getPropertyPath (),
240
326
$ errors [1 ]->getCause ()->getPropertyPath (),
241
327
$ errors [2 ]->getCause ()->getPropertyPath (),
242
328
];
243
329
330
+ $ this ->assertTrue ($ form ->get ('authors ' )->has ('0 ' ));
244
331
$ this ->assertContains ('data.authors[0].firstName ' , $ errorPaths );
245
- $ this ->assertNotContains ('data.authors[1].firstName ' , $ errorPaths );
332
+
333
+ $ this ->assertTrue ($ form ->get ('authors ' )->has ('1 ' ));
334
+ $ this ->assertContains ('data.authors[1].firstName ' , $ errorPaths );
335
+
336
+ $ this ->assertTrue ($ form ->get ('authors ' )->has ('2 ' ));
246
337
$ this ->assertContains ('data.authors[2].firstName ' , $ errorPaths );
247
- $ this ->assertContains ('data.authors[3].firstName ' , $ errorPaths );
248
338
249
- //In fact, root form should NOT contain errors but it does
339
+ $ this ->assertFalse ($ form ->get ('authors ' )->has ('3 ' ));
340
+ $ this ->assertNotContains ('data.authors[3].firstName ' , $ errorPaths );
341
+
342
+ // Root form does NOT contain errors
250
343
$ this ->assertCount (0 , $ form ->getErrors (false ));
251
344
}
252
345
}
0 commit comments