]>
Commit | Line | Data |
---|---|---|
4f5b44bd NL |
1 | <?php |
2 | ||
3 | /* | |
4 | * This file is part of the Symfony package. | |
5 | * | |
6 | * (c) Fabien Potencier <fabien@symfony.com> | |
7 | * | |
8 | * For the full copyright and license information, please view the LICENSE | |
9 | * file that was distributed with this source code. | |
10 | */ | |
11 | ||
12 | namespace Symfony\Component\Form\Tests; | |
13 | ||
14 | use Symfony\Component\Form\Form; | |
15 | use Symfony\Component\Form\FormEvent; | |
16 | use Symfony\Component\Form\FormEvents; | |
17 | use Symfony\Component\PropertyAccess\PropertyPath; | |
18 | use Symfony\Component\Form\FormConfigBuilder; | |
19 | use Symfony\Component\Form\FormError; | |
20 | use Symfony\Component\Form\Exception\TransformationFailedException; | |
21 | use Symfony\Component\EventDispatcher\EventDispatcher; | |
22 | use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; | |
23 | use Symfony\Component\Form\Tests\Fixtures\FixedFilterListener; | |
24 | ||
25 | class SimpleFormTest_Countable implements \Countable | |
26 | { | |
27 | private $count; | |
28 | ||
29 | public function __construct($count) | |
30 | { | |
31 | $this->count = $count; | |
32 | } | |
33 | ||
34 | public function count() | |
35 | { | |
36 | return $this->count; | |
37 | } | |
38 | } | |
39 | ||
40 | class SimpleFormTest_Traversable implements \IteratorAggregate | |
41 | { | |
42 | private $iterator; | |
43 | ||
44 | public function __construct($count) | |
45 | { | |
46 | $this->iterator = new \ArrayIterator($count > 0 ? array_fill(0, $count, 'Foo') : array()); | |
47 | } | |
48 | ||
49 | public function getIterator() | |
50 | { | |
51 | return $this->iterator; | |
52 | } | |
53 | } | |
54 | ||
55 | class SimpleFormTest extends AbstractFormTest | |
56 | { | |
57 | public function testDataIsInitializedToConfiguredValue() | |
58 | { | |
59 | $model = new FixedDataTransformer(array( | |
60 | 'default' => 'foo', | |
61 | )); | |
62 | $view = new FixedDataTransformer(array( | |
63 | 'foo' => 'bar', | |
64 | )); | |
65 | ||
66 | $config = new FormConfigBuilder('name', null, $this->dispatcher); | |
67 | $config->addViewTransformer($view); | |
68 | $config->addModelTransformer($model); | |
69 | $config->setData('default'); | |
70 | $form = new Form($config); | |
71 | ||
72 | $this->assertSame('default', $form->getData()); | |
73 | $this->assertSame('foo', $form->getNormData()); | |
74 | $this->assertSame('bar', $form->getViewData()); | |
75 | } | |
76 | ||
77 | // https://github.com/symfony/symfony/commit/d4f4038f6daf7cf88ca7c7ab089473cce5ebf7d8#commitcomment-1632879 | |
78 | public function testDataIsInitializedFromSubmit() | |
79 | { | |
80 | $mock = $this->getMockBuilder('\stdClass') | |
81 | ->setMethods(array('preSetData', 'preSubmit')) | |
82 | ->getMock(); | |
83 | $mock->expects($this->at(0)) | |
84 | ->method('preSetData'); | |
85 | $mock->expects($this->at(1)) | |
86 | ->method('preSubmit'); | |
87 | ||
88 | $config = new FormConfigBuilder('name', null, $this->dispatcher); | |
89 | $config->addEventListener(FormEvents::PRE_SET_DATA, array($mock, 'preSetData')); | |
90 | $config->addEventListener(FormEvents::PRE_SUBMIT, array($mock, 'preSubmit')); | |
91 | $form = new Form($config); | |
92 | ||
93 | // no call to setData() or similar where the object would be | |
94 | // initialized otherwise | |
95 | ||
96 | $form->submit('foobar'); | |
97 | } | |
98 | ||
99 | // https://github.com/symfony/symfony/pull/7789 | |
100 | public function testFalseIsConvertedToNull() | |
101 | { | |
102 | $mock = $this->getMockBuilder('\stdClass') | |
103 | ->setMethods(array('preBind')) | |
104 | ->getMock(); | |
105 | $mock->expects($this->once()) | |
106 | ->method('preBind') | |
107 | ->with($this->callback(function ($event) { | |
108 | return null === $event->getData(); | |
109 | })); | |
110 | ||
111 | $config = new FormConfigBuilder('name', null, $this->dispatcher); | |
112 | $config->addEventListener(FormEvents::PRE_BIND, array($mock, 'preBind')); | |
113 | $form = new Form($config); | |
114 | ||
115 | $form->bind(false); | |
116 | ||
117 | $this->assertTrue($form->isValid()); | |
118 | $this->assertNull($form->getData()); | |
119 | } | |
120 | ||
121 | /** | |
122 | * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException | |
123 | */ | |
124 | public function testSubmitThrowsExceptionIfAlreadySubmitted() | |
125 | { | |
126 | $this->form->submit(array()); | |
127 | $this->form->submit(array()); | |
128 | } | |
129 | ||
130 | public function testSubmitIsIgnoredIfDisabled() | |
131 | { | |
132 | $form = $this->getBuilder() | |
133 | ->setDisabled(true) | |
134 | ->setData('initial') | |
135 | ->getForm(); | |
136 | ||
137 | $form->submit('new'); | |
138 | ||
139 | $this->assertEquals('initial', $form->getData()); | |
140 | $this->assertTrue($form->isSubmitted()); | |
141 | } | |
142 | ||
143 | public function testNeverRequiredIfParentNotRequired() | |
144 | { | |
145 | $parent = $this->getBuilder()->setRequired(false)->getForm(); | |
146 | $child = $this->getBuilder()->setRequired(true)->getForm(); | |
147 | ||
148 | $child->setParent($parent); | |
149 | ||
150 | $this->assertFalse($child->isRequired()); | |
151 | } | |
152 | ||
153 | public function testRequired() | |
154 | { | |
155 | $parent = $this->getBuilder()->setRequired(true)->getForm(); | |
156 | $child = $this->getBuilder()->setRequired(true)->getForm(); | |
157 | ||
158 | $child->setParent($parent); | |
159 | ||
160 | $this->assertTrue($child->isRequired()); | |
161 | } | |
162 | ||
163 | public function testNotRequired() | |
164 | { | |
165 | $parent = $this->getBuilder()->setRequired(true)->getForm(); | |
166 | $child = $this->getBuilder()->setRequired(false)->getForm(); | |
167 | ||
168 | $child->setParent($parent); | |
169 | ||
170 | $this->assertFalse($child->isRequired()); | |
171 | } | |
172 | ||
173 | public function testAlwaysDisabledIfParentDisabled() | |
174 | { | |
175 | $parent = $this->getBuilder()->setDisabled(true)->getForm(); | |
176 | $child = $this->getBuilder()->setDisabled(false)->getForm(); | |
177 | ||
178 | $child->setParent($parent); | |
179 | ||
180 | $this->assertTrue($child->isDisabled()); | |
181 | } | |
182 | ||
183 | public function testDisabled() | |
184 | { | |
185 | $parent = $this->getBuilder()->setDisabled(false)->getForm(); | |
186 | $child = $this->getBuilder()->setDisabled(true)->getForm(); | |
187 | ||
188 | $child->setParent($parent); | |
189 | ||
190 | $this->assertTrue($child->isDisabled()); | |
191 | } | |
192 | ||
193 | public function testNotDisabled() | |
194 | { | |
195 | $parent = $this->getBuilder()->setDisabled(false)->getForm(); | |
196 | $child = $this->getBuilder()->setDisabled(false)->getForm(); | |
197 | ||
198 | $child->setParent($parent); | |
199 | ||
200 | $this->assertFalse($child->isDisabled()); | |
201 | } | |
202 | ||
203 | public function testGetRootReturnsRootOfParent() | |
204 | { | |
205 | $parent = $this->getMockForm(); | |
206 | $parent->expects($this->once()) | |
207 | ->method('getRoot') | |
208 | ->will($this->returnValue('ROOT')); | |
209 | ||
210 | $this->form->setParent($parent); | |
211 | ||
212 | $this->assertEquals('ROOT', $this->form->getRoot()); | |
213 | } | |
214 | ||
215 | public function testGetRootReturnsSelfIfNoParent() | |
216 | { | |
217 | $this->assertSame($this->form, $this->form->getRoot()); | |
218 | } | |
219 | ||
220 | public function testEmptyIfEmptyArray() | |
221 | { | |
222 | $this->form->setData(array()); | |
223 | ||
224 | $this->assertTrue($this->form->isEmpty()); | |
225 | } | |
226 | ||
227 | public function testEmptyIfEmptyCountable() | |
228 | { | |
229 | $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher)); | |
230 | ||
231 | $this->form->setData(new SimpleFormTest_Countable(0)); | |
232 | ||
233 | $this->assertTrue($this->form->isEmpty()); | |
234 | } | |
235 | ||
236 | public function testNotEmptyIfFilledCountable() | |
237 | { | |
238 | $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher)); | |
239 | ||
240 | $this->form->setData(new SimpleFormTest_Countable(1)); | |
241 | ||
242 | $this->assertFalse($this->form->isEmpty()); | |
243 | } | |
244 | ||
245 | public function testEmptyIfEmptyTraversable() | |
246 | { | |
247 | $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher)); | |
248 | ||
249 | $this->form->setData(new SimpleFormTest_Traversable(0)); | |
250 | ||
251 | $this->assertTrue($this->form->isEmpty()); | |
252 | } | |
253 | ||
254 | public function testNotEmptyIfFilledTraversable() | |
255 | { | |
256 | $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher)); | |
257 | ||
258 | $this->form->setData(new SimpleFormTest_Traversable(1)); | |
259 | ||
260 | $this->assertFalse($this->form->isEmpty()); | |
261 | } | |
262 | ||
263 | public function testEmptyIfNull() | |
264 | { | |
265 | $this->form->setData(null); | |
266 | ||
267 | $this->assertTrue($this->form->isEmpty()); | |
268 | } | |
269 | ||
270 | public function testEmptyIfEmptyString() | |
271 | { | |
272 | $this->form->setData(''); | |
273 | ||
274 | $this->assertTrue($this->form->isEmpty()); | |
275 | } | |
276 | ||
277 | public function testNotEmptyIfText() | |
278 | { | |
279 | $this->form->setData('foobar'); | |
280 | ||
281 | $this->assertFalse($this->form->isEmpty()); | |
282 | } | |
283 | ||
284 | public function testValidIfSubmitted() | |
285 | { | |
286 | $form = $this->getBuilder()->getForm(); | |
287 | $form->submit('foobar'); | |
288 | ||
289 | $this->assertTrue($form->isValid()); | |
290 | } | |
291 | ||
292 | public function testValidIfSubmittedAndDisabled() | |
293 | { | |
294 | $form = $this->getBuilder()->setDisabled(true)->getForm(); | |
295 | $form->submit('foobar'); | |
296 | ||
297 | $this->assertTrue($form->isValid()); | |
298 | } | |
299 | ||
300 | public function testNotValidIfNotSubmitted() | |
301 | { | |
302 | $this->assertFalse($this->form->isValid()); | |
303 | } | |
304 | ||
305 | public function testNotValidIfErrors() | |
306 | { | |
307 | $form = $this->getBuilder()->getForm(); | |
308 | $form->submit('foobar'); | |
309 | $form->addError(new FormError('Error!')); | |
310 | ||
311 | $this->assertFalse($form->isValid()); | |
312 | } | |
313 | ||
314 | public function testHasErrors() | |
315 | { | |
316 | $this->form->addError(new FormError('Error!')); | |
317 | ||
318 | $this->assertCount(1, $this->form->getErrors()); | |
319 | } | |
320 | ||
321 | public function testHasNoErrors() | |
322 | { | |
323 | $this->assertCount(0, $this->form->getErrors()); | |
324 | } | |
325 | ||
326 | /** | |
327 | * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException | |
328 | */ | |
329 | public function testSetParentThrowsExceptionIfAlreadySubmitted() | |
330 | { | |
331 | $this->form->submit(array()); | |
332 | $this->form->setParent($this->getBuilder('parent')->getForm()); | |
333 | } | |
334 | ||
335 | public function testSubmitted() | |
336 | { | |
337 | $form = $this->getBuilder()->getForm(); | |
338 | $form->submit('foobar'); | |
339 | ||
340 | $this->assertTrue($form->isSubmitted()); | |
341 | } | |
342 | ||
343 | public function testNotSubmitted() | |
344 | { | |
345 | $this->assertFalse($this->form->isSubmitted()); | |
346 | } | |
347 | ||
348 | /** | |
349 | * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException | |
350 | */ | |
351 | public function testSetDataThrowsExceptionIfAlreadySubmitted() | |
352 | { | |
353 | $this->form->submit(array()); | |
354 | $this->form->setData(null); | |
355 | } | |
356 | ||
357 | public function testSetDataClonesObjectIfNotByReference() | |
358 | { | |
359 | $data = new \stdClass(); | |
360 | $form = $this->getBuilder('name', null, '\stdClass')->setByReference(false)->getForm(); | |
361 | $form->setData($data); | |
362 | ||
363 | $this->assertNotSame($data, $form->getData()); | |
364 | $this->assertEquals($data, $form->getData()); | |
365 | } | |
366 | ||
367 | public function testSetDataDoesNotCloneObjectIfByReference() | |
368 | { | |
369 | $data = new \stdClass(); | |
370 | $form = $this->getBuilder('name', null, '\stdClass')->setByReference(true)->getForm(); | |
371 | $form->setData($data); | |
372 | ||
373 | $this->assertSame($data, $form->getData()); | |
374 | } | |
375 | ||
376 | public function testSetDataExecutesTransformationChain() | |
377 | { | |
378 | // use real event dispatcher now | |
379 | $form = $this->getBuilder('name', new EventDispatcher()) | |
380 | ->addEventSubscriber(new FixedFilterListener(array( | |
381 | 'preSetData' => array( | |
382 | 'app' => 'filtered', | |
383 | ), | |
384 | ))) | |
385 | ->addModelTransformer(new FixedDataTransformer(array( | |
386 | '' => '', | |
387 | 'filtered' => 'norm', | |
388 | ))) | |
389 | ->addViewTransformer(new FixedDataTransformer(array( | |
390 | '' => '', | |
391 | 'norm' => 'client', | |
392 | ))) | |
393 | ->getForm(); | |
394 | ||
395 | $form->setData('app'); | |
396 | ||
397 | $this->assertEquals('filtered', $form->getData()); | |
398 | $this->assertEquals('norm', $form->getNormData()); | |
399 | $this->assertEquals('client', $form->getViewData()); | |
400 | } | |
401 | ||
402 | public function testSetDataExecutesViewTransformersInOrder() | |
403 | { | |
404 | $form = $this->getBuilder() | |
405 | ->addViewTransformer(new FixedDataTransformer(array( | |
406 | '' => '', | |
407 | 'first' => 'second', | |
408 | ))) | |
409 | ->addViewTransformer(new FixedDataTransformer(array( | |
410 | '' => '', | |
411 | 'second' => 'third', | |
412 | ))) | |
413 | ->getForm(); | |
414 | ||
415 | $form->setData('first'); | |
416 | ||
417 | $this->assertEquals('third', $form->getViewData()); | |
418 | } | |
419 | ||
420 | public function testSetDataExecutesModelTransformersInReverseOrder() | |
421 | { | |
422 | $form = $this->getBuilder() | |
423 | ->addModelTransformer(new FixedDataTransformer(array( | |
424 | '' => '', | |
425 | 'second' => 'third', | |
426 | ))) | |
427 | ->addModelTransformer(new FixedDataTransformer(array( | |
428 | '' => '', | |
429 | 'first' => 'second', | |
430 | ))) | |
431 | ->getForm(); | |
432 | ||
433 | $form->setData('first'); | |
434 | ||
435 | $this->assertEquals('third', $form->getNormData()); | |
436 | } | |
437 | ||
438 | /* | |
439 | * When there is no data transformer, the data must have the same format | |
440 | * in all three representations | |
441 | */ | |
442 | public function testSetDataConvertsScalarToStringIfNoTransformer() | |
443 | { | |
444 | $form = $this->getBuilder()->getForm(); | |
445 | ||
446 | $form->setData(1); | |
447 | ||
448 | $this->assertSame('1', $form->getData()); | |
449 | $this->assertSame('1', $form->getNormData()); | |
450 | $this->assertSame('1', $form->getViewData()); | |
451 | } | |
452 | ||
453 | /* | |
454 | * Data in client format should, if possible, always be a string to | |
455 | * facilitate differentiation between '0' and '' | |
456 | */ | |
457 | public function testSetDataConvertsScalarToStringIfOnlyModelTransformer() | |
458 | { | |
459 | $form = $this->getBuilder() | |
460 | ->addModelTransformer(new FixedDataTransformer(array( | |
461 | '' => '', | |
462 | 1 => 23, | |
463 | ))) | |
464 | ->getForm(); | |
465 | ||
466 | $form->setData(1); | |
467 | ||
468 | $this->assertSame(1, $form->getData()); | |
469 | $this->assertSame(23, $form->getNormData()); | |
470 | $this->assertSame('23', $form->getViewData()); | |
471 | } | |
472 | ||
473 | /* | |
474 | * NULL remains NULL in app and norm format to remove the need to treat | |
475 | * empty values and NULL explicitly in the application | |
476 | */ | |
477 | public function testSetDataConvertsNullToStringIfNoTransformer() | |
478 | { | |
479 | $form = $this->getBuilder()->getForm(); | |
480 | ||
481 | $form->setData(null); | |
482 | ||
483 | $this->assertNull($form->getData()); | |
484 | $this->assertNull($form->getNormData()); | |
485 | $this->assertSame('', $form->getViewData()); | |
486 | } | |
487 | ||
488 | public function testSetDataIsIgnoredIfDataIsLocked() | |
489 | { | |
490 | $form = $this->getBuilder() | |
491 | ->setData('default') | |
492 | ->setDataLocked(true) | |
493 | ->getForm(); | |
494 | ||
495 | $form->setData('foobar'); | |
496 | ||
497 | $this->assertSame('default', $form->getData()); | |
498 | } | |
499 | ||
500 | public function testSubmitConvertsEmptyToNullIfNoTransformer() | |
501 | { | |
502 | $form = $this->getBuilder()->getForm(); | |
503 | ||
504 | $form->submit(''); | |
505 | ||
506 | $this->assertNull($form->getData()); | |
507 | $this->assertNull($form->getNormData()); | |
508 | $this->assertSame('', $form->getViewData()); | |
509 | } | |
510 | ||
511 | public function testSubmitExecutesTransformationChain() | |
512 | { | |
513 | // use real event dispatcher now | |
514 | $form = $this->getBuilder('name', new EventDispatcher()) | |
515 | ->addEventSubscriber(new FixedFilterListener(array( | |
516 | 'preSubmit' => array( | |
517 | 'client' => 'filteredclient', | |
518 | ), | |
519 | 'onSubmit' => array( | |
520 | 'norm' => 'filterednorm', | |
521 | ), | |
522 | ))) | |
523 | ->addViewTransformer(new FixedDataTransformer(array( | |
524 | '' => '', | |
525 | // direction is reversed! | |
526 | 'norm' => 'filteredclient', | |
527 | 'filterednorm' => 'cleanedclient' | |
528 | ))) | |
529 | ->addModelTransformer(new FixedDataTransformer(array( | |
530 | '' => '', | |
531 | // direction is reversed! | |
532 | 'app' => 'filterednorm', | |
533 | ))) | |
534 | ->getForm(); | |
535 | ||
536 | $form->submit('client'); | |
537 | ||
538 | $this->assertEquals('app', $form->getData()); | |
539 | $this->assertEquals('filterednorm', $form->getNormData()); | |
540 | $this->assertEquals('cleanedclient', $form->getViewData()); | |
541 | } | |
542 | ||
543 | public function testSubmitExecutesViewTransformersInReverseOrder() | |
544 | { | |
545 | $form = $this->getBuilder() | |
546 | ->addViewTransformer(new FixedDataTransformer(array( | |
547 | '' => '', | |
548 | 'third' => 'second', | |
549 | ))) | |
550 | ->addViewTransformer(new FixedDataTransformer(array( | |
551 | '' => '', | |
552 | 'second' => 'first', | |
553 | ))) | |
554 | ->getForm(); | |
555 | ||
556 | $form->submit('first'); | |
557 | ||
558 | $this->assertEquals('third', $form->getNormData()); | |
559 | } | |
560 | ||
561 | public function testSubmitExecutesModelTransformersInOrder() | |
562 | { | |
563 | $form = $this->getBuilder() | |
564 | ->addModelTransformer(new FixedDataTransformer(array( | |
565 | '' => '', | |
566 | 'second' => 'first', | |
567 | ))) | |
568 | ->addModelTransformer(new FixedDataTransformer(array( | |
569 | '' => '', | |
570 | 'third' => 'second', | |
571 | ))) | |
572 | ->getForm(); | |
573 | ||
574 | $form->submit('first'); | |
575 | ||
576 | $this->assertEquals('third', $form->getData()); | |
577 | } | |
578 | ||
579 | public function testSynchronizedByDefault() | |
580 | { | |
581 | $this->assertTrue($this->form->isSynchronized()); | |
582 | } | |
583 | ||
584 | public function testSynchronizedAfterSubmission() | |
585 | { | |
586 | $this->form->submit('foobar'); | |
587 | ||
588 | $this->assertTrue($this->form->isSynchronized()); | |
589 | } | |
590 | ||
591 | public function testNotSynchronizedIfViewReverseTransformationFailed() | |
592 | { | |
593 | $transformer = $this->getDataTransformer(); | |
594 | $transformer->expects($this->once()) | |
595 | ->method('reverseTransform') | |
596 | ->will($this->throwException(new TransformationFailedException())); | |
597 | ||
598 | $form = $this->getBuilder() | |
599 | ->addViewTransformer($transformer) | |
600 | ->getForm(); | |
601 | ||
602 | $form->submit('foobar'); | |
603 | ||
604 | $this->assertFalse($form->isSynchronized()); | |
605 | } | |
606 | ||
607 | public function testNotSynchronizedIfModelReverseTransformationFailed() | |
608 | { | |
609 | $transformer = $this->getDataTransformer(); | |
610 | $transformer->expects($this->once()) | |
611 | ->method('reverseTransform') | |
612 | ->will($this->throwException(new TransformationFailedException())); | |
613 | ||
614 | $form = $this->getBuilder() | |
615 | ->addModelTransformer($transformer) | |
616 | ->getForm(); | |
617 | ||
618 | $form->submit('foobar'); | |
619 | ||
620 | $this->assertFalse($form->isSynchronized()); | |
621 | } | |
622 | ||
623 | public function testEmptyDataCreatedBeforeTransforming() | |
624 | { | |
625 | $form = $this->getBuilder() | |
626 | ->setEmptyData('foo') | |
627 | ->addViewTransformer(new FixedDataTransformer(array( | |
628 | '' => '', | |
629 | // direction is reversed! | |
630 | 'bar' => 'foo', | |
631 | ))) | |
632 | ->getForm(); | |
633 | ||
634 | $form->submit(''); | |
635 | ||
636 | $this->assertEquals('bar', $form->getData()); | |
637 | } | |
638 | ||
639 | public function testEmptyDataFromClosure() | |
640 | { | |
641 | $test = $this; | |
642 | $form = $this->getBuilder() | |
643 | ->setEmptyData(function ($form) use ($test) { | |
644 | // the form instance is passed to the closure to allow use | |
645 | // of form data when creating the empty value | |
646 | $test->assertInstanceOf('Symfony\Component\Form\FormInterface', $form); | |
647 | ||
648 | return 'foo'; | |
649 | }) | |
650 | ->addViewTransformer(new FixedDataTransformer(array( | |
651 | '' => '', | |
652 | // direction is reversed! | |
653 | 'bar' => 'foo', | |
654 | ))) | |
655 | ->getForm(); | |
656 | ||
657 | $form->submit(''); | |
658 | ||
659 | $this->assertEquals('bar', $form->getData()); | |
660 | } | |
661 | ||
662 | public function testSubmitResetsErrors() | |
663 | { | |
664 | $this->form->addError(new FormError('Error!')); | |
665 | $this->form->submit('foobar'); | |
666 | ||
667 | $this->assertSame(array(), $this->form->getErrors()); | |
668 | } | |
669 | ||
670 | public function testCreateView() | |
671 | { | |
672 | $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface'); | |
673 | $view = $this->getMock('Symfony\Component\Form\FormView'); | |
674 | $form = $this->getBuilder()->setType($type)->getForm(); | |
675 | ||
676 | $type->expects($this->once()) | |
677 | ->method('createView') | |
678 | ->with($form) | |
679 | ->will($this->returnValue($view)); | |
680 | ||
681 | $this->assertSame($view, $form->createView()); | |
682 | } | |
683 | ||
684 | public function testCreateViewWithParent() | |
685 | { | |
686 | $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface'); | |
687 | $view = $this->getMock('Symfony\Component\Form\FormView'); | |
688 | $parentForm = $this->getMock('Symfony\Component\Form\Test\FormInterface'); | |
689 | $parentView = $this->getMock('Symfony\Component\Form\FormView'); | |
690 | $form = $this->getBuilder()->setType($type)->getForm(); | |
691 | $form->setParent($parentForm); | |
692 | ||
693 | $parentForm->expects($this->once()) | |
694 | ->method('createView') | |
695 | ->will($this->returnValue($parentView)); | |
696 | ||
697 | $type->expects($this->once()) | |
698 | ->method('createView') | |
699 | ->with($form, $parentView) | |
700 | ->will($this->returnValue($view)); | |
701 | ||
702 | $this->assertSame($view, $form->createView()); | |
703 | } | |
704 | ||
705 | public function testCreateViewWithExplicitParent() | |
706 | { | |
707 | $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface'); | |
708 | $view = $this->getMock('Symfony\Component\Form\FormView'); | |
709 | $parentView = $this->getMock('Symfony\Component\Form\FormView'); | |
710 | $form = $this->getBuilder()->setType($type)->getForm(); | |
711 | ||
712 | $type->expects($this->once()) | |
713 | ->method('createView') | |
714 | ->with($form, $parentView) | |
715 | ->will($this->returnValue($view)); | |
716 | ||
717 | $this->assertSame($view, $form->createView($parentView)); | |
718 | } | |
719 | ||
720 | public function testGetErrorsAsString() | |
721 | { | |
722 | $this->form->addError(new FormError('Error!')); | |
723 | ||
724 | $this->assertEquals("ERROR: Error!\n", $this->form->getErrorsAsString()); | |
725 | } | |
726 | ||
727 | public function testFormCanHaveEmptyName() | |
728 | { | |
729 | $form = $this->getBuilder('')->getForm(); | |
730 | ||
731 | $this->assertEquals('', $form->getName()); | |
732 | } | |
733 | ||
734 | public function testSetNullParentWorksWithEmptyName() | |
735 | { | |
736 | $form = $this->getBuilder('')->getForm(); | |
737 | $form->setParent(null); | |
738 | ||
739 | $this->assertNull($form->getParent()); | |
740 | } | |
741 | ||
742 | /** | |
743 | * @expectedException \Symfony\Component\Form\Exception\LogicException | |
744 | * @expectedExceptionMessage A form with an empty name cannot have a parent form. | |
745 | */ | |
746 | public function testFormCannotHaveEmptyNameNotInRootLevel() | |
747 | { | |
748 | $this->getBuilder() | |
749 | ->setCompound(true) | |
750 | ->setDataMapper($this->getDataMapper()) | |
751 | ->add($this->getBuilder('')) | |
752 | ->getForm(); | |
753 | } | |
754 | ||
755 | public function testGetPropertyPathReturnsConfiguredPath() | |
756 | { | |
757 | $form = $this->getBuilder()->setPropertyPath('address.street')->getForm(); | |
758 | ||
759 | $this->assertEquals(new PropertyPath('address.street'), $form->getPropertyPath()); | |
760 | } | |
761 | ||
762 | // see https://github.com/symfony/symfony/issues/3903 | |
763 | public function testGetPropertyPathDefaultsToNameIfParentHasDataClass() | |
764 | { | |
765 | $parent = $this->getBuilder(null, null, 'stdClass') | |
766 | ->setCompound(true) | |
767 | ->setDataMapper($this->getDataMapper()) | |
768 | ->getForm(); | |
769 | $form = $this->getBuilder('name')->getForm(); | |
770 | $parent->add($form); | |
771 | ||
772 | $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath()); | |
773 | } | |
774 | ||
775 | // see https://github.com/symfony/symfony/issues/3903 | |
776 | public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull() | |
777 | { | |
778 | $parent = $this->getBuilder() | |
779 | ->setCompound(true) | |
780 | ->setDataMapper($this->getDataMapper()) | |
781 | ->getForm(); | |
782 | $form = $this->getBuilder('name')->getForm(); | |
783 | $parent->add($form); | |
784 | ||
785 | $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath()); | |
786 | } | |
787 | ||
788 | public function testGetPropertyPathDefaultsToNameIfFirstParentWithoutInheritDataHasDataClass() | |
789 | { | |
790 | $grandParent = $this->getBuilder(null, null, 'stdClass') | |
791 | ->setCompound(true) | |
792 | ->setDataMapper($this->getDataMapper()) | |
793 | ->getForm(); | |
794 | $parent = $this->getBuilder() | |
795 | ->setCompound(true) | |
796 | ->setDataMapper($this->getDataMapper()) | |
797 | ->setInheritData(true) | |
798 | ->getForm(); | |
799 | $form = $this->getBuilder('name')->getForm(); | |
800 | $grandParent->add($parent); | |
801 | $parent->add($form); | |
802 | ||
803 | $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath()); | |
804 | } | |
805 | ||
806 | public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParentWithoutInheritDataIsNull() | |
807 | { | |
808 | $grandParent = $this->getBuilder() | |
809 | ->setCompound(true) | |
810 | ->setDataMapper($this->getDataMapper()) | |
811 | ->getForm(); | |
812 | $parent = $this->getBuilder() | |
813 | ->setCompound(true) | |
814 | ->setDataMapper($this->getDataMapper()) | |
815 | ->setInheritData(true) | |
816 | ->getForm(); | |
817 | $form = $this->getBuilder('name')->getForm(); | |
818 | $grandParent->add($parent); | |
819 | $parent->add($form); | |
820 | ||
821 | $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath()); | |
822 | } | |
823 | ||
824 | /** | |
825 | * @expectedException \Symfony\Component\Form\Exception\LogicException | |
826 | */ | |
827 | public function testViewDataMustNotBeObjectIfDataClassIsNull() | |
828 | { | |
829 | $config = new FormConfigBuilder('name', null, $this->dispatcher); | |
830 | $config->addViewTransformer(new FixedDataTransformer(array( | |
831 | '' => '', | |
832 | 'foo' => new \stdClass(), | |
833 | ))); | |
834 | $form = new Form($config); | |
835 | ||
836 | $form->setData('foo'); | |
837 | } | |
838 | ||
839 | public function testViewDataMayBeArrayAccessIfDataClassIsNull() | |
840 | { | |
841 | $arrayAccess = $this->getMock('\ArrayAccess'); | |
842 | $config = new FormConfigBuilder('name', null, $this->dispatcher); | |
843 | $config->addViewTransformer(new FixedDataTransformer(array( | |
844 | '' => '', | |
845 | 'foo' => $arrayAccess, | |
846 | ))); | |
847 | $form = new Form($config); | |
848 | ||
849 | $form->setData('foo'); | |
850 | ||
851 | $this->assertSame($arrayAccess, $form->getViewData()); | |
852 | } | |
853 | ||
854 | /** | |
855 | * @expectedException \Symfony\Component\Form\Exception\LogicException | |
856 | */ | |
857 | public function testViewDataMustBeObjectIfDataClassIsSet() | |
858 | { | |
859 | $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); | |
860 | $config->addViewTransformer(new FixedDataTransformer(array( | |
861 | '' => '', | |
862 | 'foo' => array('bar' => 'baz'), | |
863 | ))); | |
864 | $form = new Form($config); | |
865 | ||
866 | $form->setData('foo'); | |
867 | } | |
868 | ||
869 | /** | |
870 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
871 | */ | |
872 | public function testSetDataCannotInvokeItself() | |
873 | { | |
874 | // Cycle detection to prevent endless loops | |
875 | $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); | |
876 | $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { | |
877 | $event->getForm()->setData('bar'); | |
878 | }); | |
879 | $form = new Form($config); | |
880 | ||
881 | $form->setData('foo'); | |
882 | } | |
883 | ||
884 | public function testSubmittingWrongDataIsIgnored() | |
885 | { | |
886 | $test = $this; | |
887 | ||
888 | $child = $this->getBuilder('child', $this->dispatcher); | |
889 | $child->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($test) { | |
890 | // child form doesn't receive the wrong data that is submitted on parent | |
891 | $test->assertNull($event->getData()); | |
892 | }); | |
893 | ||
894 | $parent = $this->getBuilder('parent', new EventDispatcher()) | |
895 | ->setCompound(true) | |
896 | ->setDataMapper($this->getDataMapper()) | |
897 | ->add($child) | |
898 | ->getForm(); | |
899 | ||
900 | $parent->submit('not-an-array'); | |
901 | } | |
902 | ||
903 | public function testHandleRequestForwardsToRequestHandler() | |
904 | { | |
905 | $handler = $this->getMock('Symfony\Component\Form\RequestHandlerInterface'); | |
906 | ||
907 | $form = $this->getBuilder() | |
908 | ->setRequestHandler($handler) | |
909 | ->getForm(); | |
910 | ||
911 | $handler->expects($this->once()) | |
912 | ->method('handleRequest') | |
913 | ->with($this->identicalTo($form), 'REQUEST'); | |
914 | ||
915 | $this->assertSame($form, $form->handleRequest('REQUEST')); | |
916 | } | |
917 | ||
918 | public function testFormInheritsParentData() | |
919 | { | |
920 | $child = $this->getBuilder('child') | |
921 | ->setInheritData(true); | |
922 | ||
923 | $parent = $this->getBuilder('parent') | |
924 | ->setCompound(true) | |
925 | ->setDataMapper($this->getDataMapper()) | |
926 | ->setData('foo') | |
927 | ->addModelTransformer(new FixedDataTransformer(array( | |
928 | 'foo' => 'norm[foo]', | |
929 | ))) | |
930 | ->addViewTransformer(new FixedDataTransformer(array( | |
931 | 'norm[foo]' => 'view[foo]', | |
932 | ))) | |
933 | ->add($child) | |
934 | ->getForm(); | |
935 | ||
936 | $this->assertSame('foo', $parent->get('child')->getData()); | |
937 | $this->assertSame('norm[foo]', $parent->get('child')->getNormData()); | |
938 | $this->assertSame('view[foo]', $parent->get('child')->getViewData()); | |
939 | } | |
940 | ||
941 | /** | |
942 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
943 | */ | |
944 | public function testInheritDataDisallowsSetData() | |
945 | { | |
946 | $form = $this->getBuilder() | |
947 | ->setInheritData(true) | |
948 | ->getForm(); | |
949 | ||
950 | $form->setData('foo'); | |
951 | } | |
952 | ||
953 | /** | |
954 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
955 | */ | |
956 | public function testGetDataRequiresParentToBeSetIfInheritData() | |
957 | { | |
958 | $form = $this->getBuilder() | |
959 | ->setInheritData(true) | |
960 | ->getForm(); | |
961 | ||
962 | $form->getData(); | |
963 | } | |
964 | ||
965 | /** | |
966 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
967 | */ | |
968 | public function testGetNormDataRequiresParentToBeSetIfInheritData() | |
969 | { | |
970 | $form = $this->getBuilder() | |
971 | ->setInheritData(true) | |
972 | ->getForm(); | |
973 | ||
974 | $form->getNormData(); | |
975 | } | |
976 | ||
977 | /** | |
978 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
979 | */ | |
980 | public function testGetViewDataRequiresParentToBeSetIfInheritData() | |
981 | { | |
982 | $form = $this->getBuilder() | |
983 | ->setInheritData(true) | |
984 | ->getForm(); | |
985 | ||
986 | $form->getViewData(); | |
987 | } | |
988 | ||
989 | public function testPostSubmitDataIsNullIfInheritData() | |
990 | { | |
991 | $test = $this; | |
992 | $form = $this->getBuilder() | |
993 | ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($test) { | |
994 | $test->assertNull($event->getData()); | |
995 | }) | |
996 | ->setInheritData(true) | |
997 | ->getForm(); | |
998 | ||
999 | $form->submit('foo'); | |
1000 | } | |
1001 | ||
1002 | public function testSubmitIsNeverFiredIfInheritData() | |
1003 | { | |
1004 | $test = $this; | |
1005 | $form = $this->getBuilder() | |
1006 | ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($test) { | |
1007 | $test->fail('The SUBMIT event should not be fired'); | |
1008 | }) | |
1009 | ->setInheritData(true) | |
1010 | ->getForm(); | |
1011 | ||
1012 | $form->submit('foo'); | |
1013 | } | |
1014 | ||
1015 | public function testInitializeSetsDefaultData() | |
1016 | { | |
1017 | $config = $this->getBuilder()->setData('DEFAULT')->getFormConfig(); | |
1018 | $form = $this->getMock('Symfony\Component\Form\Form', array('setData'), array($config)); | |
1019 | ||
1020 | $form->expects($this->once()) | |
1021 | ->method('setData') | |
1022 | ->with($this->identicalTo('DEFAULT')); | |
1023 | ||
1024 | /* @var Form $form */ | |
1025 | $form->initialize(); | |
1026 | } | |
1027 | ||
1028 | /** | |
1029 | * @expectedException \Symfony\Component\Form\Exception\RuntimeException | |
1030 | */ | |
1031 | public function testInitializeFailsIfParent() | |
1032 | { | |
1033 | $parent = $this->getBuilder()->setRequired(false)->getForm(); | |
1034 | $child = $this->getBuilder()->setRequired(true)->getForm(); | |
1035 | ||
1036 | $child->setParent($parent); | |
1037 | ||
1038 | $child->initialize(); | |
1039 | } | |
1040 | ||
1041 | protected function createForm() | |
1042 | { | |
1043 | return $this->getBuilder()->getForm(); | |
1044 | } | |
1045 | } |