/tests/Symfony/Tests/Component/Form/Extension/Validator/Validator/DelegatingValidatorTest.php

https://github.com/Faianca/symfony · PHP · 699 lines · 532 code · 159 blank · 8 comment · 2 complexity · 2442fcd9ab78bd87612eb8a656ca627d MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Tests\Component\Form\Extension\Validator\Validator;
  11. use Symfony\Component\Form\FormBuilder;
  12. use Symfony\Component\Form\FormError;
  13. use Symfony\Component\Form\Util\PropertyPath;
  14. use Symfony\Component\Form\Extension\Validator\Validator\DelegatingValidator;
  15. use Symfony\Component\Form\Exception\TransformationFailedException;
  16. use Symfony\Component\Validator\ConstraintViolation;
  17. use Symfony\Component\Validator\ExecutionContext;
  18. class DelegatingValidatorTest extends \PHPUnit_Framework_TestCase
  19. {
  20. private $dispatcher;
  21. private $factory;
  22. private $builder;
  23. private $delegate;
  24. private $validator;
  25. private $message;
  26. private $params;
  27. protected function setUp()
  28. {
  29. $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
  30. $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
  31. $this->delegate = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
  32. $this->validator = new DelegatingValidator($this->delegate);
  33. $this->message = 'Message';
  34. $this->params = array('foo' => 'bar');
  35. }
  36. protected function getMockGraphWalker()
  37. {
  38. return $this->getMockBuilder('Symfony\Component\Validator\GraphWalker')
  39. ->disableOriginalConstructor()
  40. ->getMock();
  41. }
  42. protected function getMockMetadataFactory()
  43. {
  44. return $this->getMock('Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface');
  45. }
  46. protected function getMockTransformer()
  47. {
  48. return $this->getMock('Symfony\Component\Form\DataTransformerInterface', array(), array(), '', false, false);
  49. }
  50. protected function getConstraintViolation($propertyPath)
  51. {
  52. return new ConstraintViolation($this->message, $this->params, null, $propertyPath, null);
  53. }
  54. protected function getFormError()
  55. {
  56. return new FormError($this->message, $this->params);
  57. }
  58. protected function getBuilder($name = 'name', $propertyPath = null)
  59. {
  60. $builder = new FormBuilder($name, $this->factory, $this->dispatcher);
  61. $builder->setAttribute('property_path', new PropertyPath($propertyPath ?: $name));
  62. $builder->setAttribute('error_mapping', array());
  63. return $builder;
  64. }
  65. protected function getForm($name = 'name', $propertyPath = null)
  66. {
  67. return $this->getBuilder($name, $propertyPath)->getForm();
  68. }
  69. protected function getMockForm()
  70. {
  71. return $this->getMock('Symfony\Tests\Component\Form\FormInterface');
  72. }
  73. public function testUseValidateValueWhenValidationConstraintExist()
  74. {
  75. $constraint = $this->getMockForAbstractClass('Symfony\Component\Validator\Constraint');
  76. $form = $this
  77. ->getBuilder('name')
  78. ->setAttribute('validation_constraint', $constraint)
  79. ->getForm();
  80. $this->delegate->expects($this->once())->method('validateValue');
  81. $this->validator->validate($form);
  82. }
  83. public function testFormErrorsOnForm()
  84. {
  85. $form = $this->getForm();
  86. $this->delegate->expects($this->once())
  87. ->method('validate')
  88. ->will($this->returnValue(array(
  89. $this->getConstraintViolation('constrainedProp')
  90. )));
  91. $this->validator->validate($form);
  92. $this->assertEquals(array($this->getFormError()), $form->getErrors());
  93. }
  94. public function testFormErrorsOnChild()
  95. {
  96. $parent = $this->getForm();
  97. $child = $this->getForm('firstName');
  98. $parent->add($child);
  99. $this->delegate->expects($this->once())
  100. ->method('validate')
  101. ->will($this->returnValue(array(
  102. $this->getConstraintViolation('children.data.firstName')
  103. )));
  104. $this->validator->validate($parent);
  105. $this->assertFalse($parent->hasErrors());
  106. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  107. }
  108. public function testFormErrorsOnChildLongPropertyPath()
  109. {
  110. $parent = $this->getForm();
  111. $child = $this->getForm('street', 'address.street');
  112. $parent->add($child);
  113. $this->delegate->expects($this->once())
  114. ->method('validate')
  115. ->will($this->returnValue(array(
  116. $this->getConstraintViolation('children[address].data.street.constrainedProp')
  117. )));
  118. $this->validator->validate($parent);
  119. $this->assertFalse($parent->hasErrors());
  120. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  121. }
  122. public function testFormErrorsOnGrandChild()
  123. {
  124. $parent = $this->getForm();
  125. $child = $this->getForm('address');
  126. $grandChild = $this->getForm('street');
  127. $parent->add($child);
  128. $child->add($grandChild);
  129. $this->delegate->expects($this->once())
  130. ->method('validate')
  131. ->will($this->returnValue(array(
  132. $this->getConstraintViolation('children[address].data.street')
  133. )));
  134. $this->validator->validate($parent);
  135. $this->assertFalse($parent->hasErrors());
  136. $this->assertFalse($child->hasErrors());
  137. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  138. }
  139. public function testFormErrorsOnChildWithChildren()
  140. {
  141. $parent = $this->getForm();
  142. $child = $this->getForm('address');
  143. $grandChild = $this->getForm('street');
  144. $parent->add($child);
  145. $child->add($grandChild);
  146. $this->delegate->expects($this->once())
  147. ->method('validate')
  148. ->will($this->returnValue(array(
  149. $this->getConstraintViolation('children[address].constrainedProp')
  150. )));
  151. $this->validator->validate($parent);
  152. $this->assertFalse($parent->hasErrors());
  153. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  154. $this->assertFalse($grandChild->hasErrors());
  155. }
  156. public function testFormErrorsOnParentIfNoChildFound()
  157. {
  158. $parent = $this->getForm();
  159. $child = $this->getForm('firstName');
  160. $parent->add($child);
  161. $this->delegate->expects($this->once())
  162. ->method('validate')
  163. ->will($this->returnValue(array(
  164. $this->getConstraintViolation('children[lastName].constrainedProp')
  165. )));
  166. $this->validator->validate($parent);
  167. $this->assertEquals(array($this->getFormError()), $parent->getErrors());
  168. $this->assertFalse($child->hasErrors());
  169. }
  170. public function testFormErrorsOnCollectionForm()
  171. {
  172. $parent = $this->getForm();
  173. for ($i = 0; $i < 2; $i++) {
  174. $child = $this->getForm((string)$i, '['.$i.']');
  175. $child->add($this->getForm('firstName'));
  176. $parent->add($child);
  177. }
  178. $this->delegate->expects($this->once())
  179. ->method('validate')
  180. ->will($this->returnValue(array(
  181. $this->getConstraintViolation('children[0].data.firstName'),
  182. $this->getConstraintViolation('children[1].data.firstName'),
  183. )));
  184. $this->validator->validate($parent);
  185. $this->assertFalse($parent->hasErrors());
  186. foreach ($parent as $child) {
  187. $grandChild = $child->get('firstName');
  188. $this->assertFalse($child->hasErrors());
  189. $this->assertTrue($grandChild->hasErrors());
  190. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  191. }
  192. }
  193. public function testDataErrorsOnForm()
  194. {
  195. $form = $this->getForm();
  196. $this->delegate->expects($this->once())
  197. ->method('validate')
  198. ->will($this->returnValue(array(
  199. $this->getConstraintViolation('data.constrainedProp')
  200. )));
  201. $this->validator->validate($form);
  202. $this->assertEquals(array($this->getFormError()), $form->getErrors());
  203. }
  204. public function testDataErrorsOnChild()
  205. {
  206. $parent = $this->getForm();
  207. $child = $this->getForm('firstName');
  208. $parent->add($child);
  209. $this->delegate->expects($this->once())
  210. ->method('validate')
  211. ->will($this->returnValue(array(
  212. $this->getConstraintViolation('data.firstName.constrainedProp')
  213. )));
  214. $this->validator->validate($parent);
  215. $this->assertFalse($parent->hasErrors());
  216. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  217. }
  218. public function testDataErrorsOnChildLongPropertyPath()
  219. {
  220. $parent = $this->getForm();
  221. $child = $this->getForm('street', 'address.street');
  222. $parent->add($child);
  223. $this->delegate->expects($this->once())
  224. ->method('validate')
  225. ->will($this->returnValue(array(
  226. $this->getConstraintViolation('data.address.street.constrainedProp')
  227. )));
  228. $this->validator->validate($parent);
  229. $this->assertFalse($parent->hasErrors());
  230. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  231. }
  232. public function testDataErrorsOnChildWithChildren()
  233. {
  234. $parent = $this->getForm();
  235. $child = $this->getForm('address');
  236. $grandChild = $this->getForm('street');
  237. $parent->add($child);
  238. $child->add($grandChild);
  239. $this->delegate->expects($this->once())
  240. ->method('validate')
  241. ->will($this->returnValue(array(
  242. $this->getConstraintViolation('data.address.constrainedProp')
  243. )));
  244. $this->validator->validate($parent);
  245. $this->assertFalse($parent->hasErrors());
  246. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  247. $this->assertFalse($grandChild->hasErrors());
  248. }
  249. public function testDataErrorsOnGrandChild()
  250. {
  251. $parent = $this->getForm();
  252. $child = $this->getForm('address');
  253. $grandChild = $this->getForm('street');
  254. $parent->add($child);
  255. $child->add($grandChild);
  256. $this->delegate->expects($this->once())
  257. ->method('validate')
  258. ->will($this->returnValue(array(
  259. $this->getConstraintViolation('data.address.street.constrainedProp')
  260. )));
  261. $this->validator->validate($parent);
  262. $this->assertFalse($parent->hasErrors());
  263. $this->assertFalse($child->hasErrors());
  264. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  265. }
  266. public function testDataErrorsOnGrandChild2()
  267. {
  268. $parent = $this->getForm();
  269. $child = $this->getForm('address');
  270. $grandChild = $this->getForm('street');
  271. $parent->add($child);
  272. $child->add($grandChild);
  273. $this->delegate->expects($this->once())
  274. ->method('validate')
  275. ->will($this->returnValue(array(
  276. $this->getConstraintViolation('children[address].data.street.constrainedProp')
  277. )));
  278. $this->validator->validate($parent);
  279. $this->assertFalse($parent->hasErrors());
  280. $this->assertFalse($child->hasErrors());
  281. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  282. }
  283. public function testDataErrorsOnGrandChild3()
  284. {
  285. $parent = $this->getForm();
  286. $child = $this->getForm('address');
  287. $grandChild = $this->getForm('street');
  288. $parent->add($child);
  289. $child->add($grandChild);
  290. $this->delegate->expects($this->once())
  291. ->method('validate')
  292. ->will($this->returnValue(array(
  293. $this->getConstraintViolation('data[address].street.constrainedProp')
  294. )));
  295. $this->validator->validate($parent);
  296. $this->assertFalse($parent->hasErrors());
  297. $this->assertFalse($child->hasErrors());
  298. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  299. }
  300. public function testDataErrorsOnParentIfNoChildFound()
  301. {
  302. $parent = $this->getForm();
  303. $child = $this->getForm('firstName');
  304. $parent->add($child);
  305. $this->delegate->expects($this->once())
  306. ->method('validate')
  307. ->will($this->returnValue(array(
  308. $this->getConstraintViolation('data.lastName.constrainedProp')
  309. )));
  310. $this->validator->validate($parent);
  311. $this->assertEquals(array($this->getFormError()), $parent->getErrors());
  312. $this->assertFalse($child->hasErrors());
  313. }
  314. public function testDataErrorsOnCollectionForm()
  315. {
  316. $parent = $this->getForm();
  317. $child = $this->getForm('addresses');
  318. $parent->add($child);
  319. for ($i = 0; $i < 2; $i++) {
  320. $collection = $this->getForm((string)$i, '['.$i.']');
  321. $collection->add($this->getForm('street'));
  322. $child->add($collection);
  323. }
  324. $this->delegate->expects($this->once())
  325. ->method('validate')
  326. ->will($this->returnValue(array(
  327. $this->getConstraintViolation('data[0].street'),
  328. $this->getConstraintViolation('data.addresses[1].street')
  329. )));
  330. $child->setData(array());
  331. $this->validator->validate($parent);
  332. $this->assertFalse($parent->hasErrors(), '->hasErrors() returns false for parent form');
  333. $this->assertFalse($child->hasErrors(), '->hasErrors() returns false for child form');
  334. foreach ($child as $collection) {
  335. $grandChild = $collection->get('street');
  336. $this->assertFalse($collection->hasErrors());
  337. $this->assertTrue($grandChild->hasErrors());
  338. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  339. }
  340. }
  341. public function testMappedError()
  342. {
  343. $parent = $this->getBuilder()
  344. ->setAttribute('error_mapping', array(
  345. 'passwordPlain' => 'password',
  346. ))
  347. ->getForm();
  348. $child = $this->getForm('password');
  349. $parent->add($child);
  350. $this->delegate->expects($this->once())
  351. ->method('validate')
  352. ->will($this->returnValue(array(
  353. $this->getConstraintViolation('data.passwordPlain.constrainedProp')
  354. )));
  355. $this->validator->validate($parent);
  356. $this->assertFalse($parent->hasErrors());
  357. $this->assertEquals(array($this->getFormError()), $child->getErrors());
  358. }
  359. public function testMappedNestedError()
  360. {
  361. $parent = $this->getBuilder()
  362. ->setAttribute('error_mapping', array(
  363. 'address.streetName' => 'address.street',
  364. ))
  365. ->getForm();
  366. $child = $this->getForm('address');
  367. $grandChild = $this->getForm('street');
  368. $parent->add($child);
  369. $child->add($grandChild);
  370. $this->delegate->expects($this->once())
  371. ->method('validate')
  372. ->will($this->returnValue(array(
  373. $this->getConstraintViolation('data.address.streetName.constrainedProp')
  374. )));
  375. $this->validator->validate($parent);
  376. $this->assertFalse($parent->hasErrors());
  377. $this->assertFalse($child->hasErrors());
  378. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  379. }
  380. public function testNestedMappingUsingForm()
  381. {
  382. $parent = $this->getForm();
  383. $child = $this->getBuilder('address')
  384. ->setAttribute('error_mapping', array(
  385. 'streetName' => 'street',
  386. ))
  387. ->getForm();
  388. $grandChild = $this->getForm('street');
  389. $parent->add($child);
  390. $child->add($grandChild);
  391. $this->delegate->expects($this->once())
  392. ->method('validate')
  393. ->will($this->returnValue(array(
  394. $this->getConstraintViolation('children[address].data.streetName.constrainedProp')
  395. )));
  396. $this->validator->validate($parent);
  397. $this->assertFalse($parent->hasErrors());
  398. $this->assertFalse($child->hasErrors());
  399. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  400. }
  401. public function testNestedMappingUsingData()
  402. {
  403. $parent = $this->getForm();
  404. $child = $this->getBuilder('address')
  405. ->setAttribute('error_mapping', array(
  406. 'streetName' => 'street',
  407. ))
  408. ->getForm();
  409. $grandChild = $this->getForm('street');
  410. $parent->add($child);
  411. $child->add($grandChild);
  412. $this->delegate->expects($this->once())
  413. ->method('validate')
  414. ->will($this->returnValue(array(
  415. $this->getConstraintViolation('data.address.streetName.constrainedProp')
  416. )));
  417. $this->validator->validate($parent);
  418. $this->assertFalse($parent->hasErrors());
  419. $this->assertFalse($child->hasErrors());
  420. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  421. }
  422. public function testNestedMappingVirtualForm()
  423. {
  424. $parent = $this->getBuilder()
  425. ->setAttribute('error_mapping', array(
  426. 'streetName' => 'street',
  427. ))
  428. ->getForm();
  429. $child = $this->getBuilder('address')
  430. ->setAttribute('virtual', true)
  431. ->getForm();
  432. $grandChild = $this->getForm('street');
  433. $parent->add($child);
  434. $child->add($grandChild);
  435. $this->delegate->expects($this->once())
  436. ->method('validate')
  437. ->will($this->returnValue(array(
  438. $this->getConstraintViolation('data.streetName.constrainedProp')
  439. )));
  440. $this->validator->validate($parent);
  441. $this->assertFalse($parent->hasErrors());
  442. $this->assertFalse($child->hasErrors());
  443. $this->assertEquals(array($this->getFormError()), $grandChild->getErrors());
  444. }
  445. public function testValidateFormData()
  446. {
  447. $graphWalker = $this->getMockGraphWalker();
  448. $metadataFactory = $this->getMockMetadataFactory();
  449. $context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
  450. $object = $this->getMock('\stdClass');
  451. $form = $this->getBuilder()
  452. ->setAttribute('validation_groups', array('group1', 'group2'))
  453. ->getForm();
  454. $graphWalker->expects($this->at(0))
  455. ->method('walkReference')
  456. ->with($object, 'group1', 'data', true);
  457. $graphWalker->expects($this->at(1))
  458. ->method('walkReference')
  459. ->with($object, 'group2', 'data', true);
  460. $form->setData($object);
  461. DelegatingValidator::validateFormData($form, $context);
  462. }
  463. public function testValidateFormDataUsesInheritedValidationGroup()
  464. {
  465. $graphWalker = $this->getMockGraphWalker();
  466. $metadataFactory = $this->getMockMetadataFactory();
  467. $context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
  468. $context->setPropertyPath('path');
  469. $object = $this->getMock('\stdClass');
  470. $parent = $this->getBuilder()
  471. ->setAttribute('validation_groups', 'group')
  472. ->getForm();
  473. $child = $this->getBuilder()
  474. ->setAttribute('validation_groups', null)
  475. ->getForm();
  476. $parent->add($child);
  477. $child->setData($object);
  478. $graphWalker->expects($this->once())
  479. ->method('walkReference')
  480. ->with($object, 'group', 'path.data', true);
  481. DelegatingValidator::validateFormData($child, $context);
  482. }
  483. public function testValidateFormDataAppendsPropertyPath()
  484. {
  485. $graphWalker = $this->getMockGraphWalker();
  486. $metadataFactory = $this->getMockMetadataFactory();
  487. $context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
  488. $context->setPropertyPath('path');
  489. $object = $this->getMock('\stdClass');
  490. $form = $this->getForm();
  491. $graphWalker->expects($this->once())
  492. ->method('walkReference')
  493. ->with($object, 'Default', 'path.data', true);
  494. $form->setData($object);
  495. DelegatingValidator::validateFormData($form, $context);
  496. }
  497. public function testValidateFormDataSetsCurrentPropertyToData()
  498. {
  499. $graphWalker = $this->getMockGraphWalker();
  500. $metadataFactory = $this->getMockMetadataFactory();
  501. $context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
  502. $object = $this->getMock('\stdClass');
  503. $form = $this->getForm();
  504. $test = $this;
  505. $graphWalker->expects($this->once())
  506. ->method('walkReference')
  507. ->will($this->returnCallback(function () use ($context, $test) {
  508. $test->assertEquals('data', $context->getCurrentProperty());
  509. }));
  510. $form->setData($object);
  511. DelegatingValidator::validateFormData($form, $context);
  512. }
  513. public function testValidateFormDataDoesNotWalkScalars()
  514. {
  515. $graphWalker = $this->getMockGraphWalker();
  516. $metadataFactory = $this->getMockMetadataFactory();
  517. $context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
  518. $clientTransformer = $this->getMockTransformer();
  519. $form = $this->getBuilder()
  520. ->appendClientTransformer($clientTransformer)
  521. ->getForm();
  522. $graphWalker->expects($this->never())
  523. ->method('walkReference');
  524. $clientTransformer->expects($this->atLeastOnce())
  525. ->method('reverseTransform')
  526. ->will($this->returnValue('foobar'));
  527. $form->bind(array('foo' => 'bar')); // reverse transformed to "foobar"
  528. DelegatingValidator::validateFormData($form, $context);
  529. }
  530. public function testValidateIgnoresNonRoot()
  531. {
  532. $form = $this->getMockForm();
  533. $form->expects($this->once())
  534. ->method('isRoot')
  535. ->will($this->returnValue(false));
  536. $this->delegate->expects($this->never())
  537. ->method('validate');
  538. $this->validator->validate($form);
  539. }
  540. }