GraphWalkerTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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\Validator;
  11. require_once __DIR__.'/Fixtures/Entity.php';
  12. require_once __DIR__.'/Fixtures/Reference.php';
  13. require_once __DIR__.'/Fixtures/ConstraintA.php';
  14. require_once __DIR__.'/Fixtures/ConstraintAValidator.php';
  15. require_once __DIR__.'/Fixtures/FailingConstraint.php';
  16. require_once __DIR__.'/Fixtures/FailingConstraintValidator.php';
  17. require_once __DIR__.'/Fixtures/FakeClassMetadataFactory.php';
  18. use Symfony\Tests\Component\Validator\Fixtures\Entity;
  19. use Symfony\Tests\Component\Validator\Fixtures\Reference;
  20. use Symfony\Tests\Component\Validator\Fixtures\FakeClassMetadataFactory;
  21. use Symfony\Tests\Component\Validator\Fixtures\ConstraintA;
  22. use Symfony\Tests\Component\Validator\Fixtures\FailingConstraint;
  23. use Symfony\Component\Validator\GraphWalker;
  24. use Symfony\Component\Validator\ConstraintViolation;
  25. use Symfony\Component\Validator\ConstraintViolationList;
  26. use Symfony\Component\Validator\ConstraintValidatorFactory;
  27. use Symfony\Component\Validator\Mapping\ClassMetadata;
  28. use Symfony\Component\Validator\Constraints\Valid;
  29. class GraphWalkerTest extends \PHPUnit_Framework_TestCase
  30. {
  31. const CLASSNAME = 'Symfony\Tests\Component\Validator\Fixtures\Entity';
  32. protected $factory;
  33. protected $walker;
  34. protected $metadata;
  35. protected function setUp()
  36. {
  37. $this->factory = new FakeClassMetadataFactory();
  38. $this->walker = new GraphWalker('Root', $this->factory, new ConstraintValidatorFactory());
  39. $this->metadata = new ClassMetadata(self::CLASSNAME);
  40. }
  41. protected function tearDown()
  42. {
  43. $this->factory = null;
  44. $this->walker = null;
  45. $this->metadata = null;
  46. }
  47. public function testWalkObjectValidatesConstraints()
  48. {
  49. $this->metadata->addConstraint(new ConstraintA());
  50. $this->walker->walkObject($this->metadata, new Entity(), 'Default', '');
  51. $this->assertEquals(1, count($this->walker->getViolations()));
  52. }
  53. public function testWalkObjectTwiceValidatesConstraintsOnce()
  54. {
  55. $this->metadata->addConstraint(new ConstraintA());
  56. $entity = new Entity();
  57. $this->walker->walkObject($this->metadata, $entity, 'Default', '');
  58. $this->walker->walkObject($this->metadata, $entity, 'Default', '');
  59. $this->assertEquals(1, count($this->walker->getViolations()));
  60. }
  61. public function testWalkDifferentObjectsValidatesTwice()
  62. {
  63. $this->metadata->addConstraint(new ConstraintA());
  64. $this->walker->walkObject($this->metadata, new Entity(), 'Default', '');
  65. $this->walker->walkObject($this->metadata, new Entity(), 'Default', '');
  66. $this->assertEquals(2, count($this->walker->getViolations()));
  67. }
  68. public function testWalkObjectTwiceInDifferentGroupsValidatesTwice()
  69. {
  70. $this->metadata->addConstraint(new ConstraintA());
  71. $this->metadata->addConstraint(new ConstraintA(array('groups' => 'Custom')));
  72. $entity = new Entity();
  73. $this->walker->walkObject($this->metadata, $entity, 'Default', '');
  74. $this->walker->walkObject($this->metadata, $entity, 'Custom', '');
  75. $this->assertEquals(2, count($this->walker->getViolations()));
  76. }
  77. public function testWalkObjectValidatesPropertyConstraints()
  78. {
  79. $this->metadata->addPropertyConstraint('firstName', new ConstraintA());
  80. $this->walker->walkObject($this->metadata, new Entity(), 'Default', '');
  81. $this->assertEquals(1, count($this->walker->getViolations()));
  82. }
  83. public function testWalkObjectValidatesGetterConstraints()
  84. {
  85. $this->metadata->addGetterConstraint('lastName', new ConstraintA());
  86. $this->walker->walkObject($this->metadata, new Entity(), 'Default', '');
  87. $this->assertEquals(1, count($this->walker->getViolations()));
  88. }
  89. public function testWalkObjectInDefaultGroupTraversesGroupSequence()
  90. {
  91. $entity = new Entity();
  92. $this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array(
  93. 'groups' => 'First',
  94. )));
  95. $this->metadata->addGetterConstraint('lastName', new FailingConstraint(array(
  96. 'groups' => 'Default',
  97. )));
  98. $this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup()));
  99. $this->walker->walkObject($this->metadata, $entity, 'Default', '');
  100. // After validation of group "First" failed, no more group was
  101. // validated
  102. $violations = new ConstraintViolationList();
  103. $violations->add(new ConstraintViolation(
  104. '',
  105. array(),
  106. 'Root',
  107. 'firstName',
  108. ''
  109. ));
  110. $this->assertEquals($violations, $this->walker->getViolations());
  111. }
  112. public function testWalkObjectInGroupSequencePropagatesDefaultGroup()
  113. {
  114. $entity = new Entity();
  115. $entity->reference = new Reference();
  116. $this->metadata->addPropertyConstraint('reference', new Valid());
  117. $this->metadata->setGroupSequence(array($this->metadata->getDefaultGroup()));
  118. $referenceMetadata = new ClassMetadata(get_class($entity->reference));
  119. $referenceMetadata->addConstraint(new FailingConstraint(array(
  120. // this constraint is only evaluated if group "Default" is
  121. // propagated to the reference
  122. 'groups' => 'Default',
  123. )));
  124. $this->factory->addClassMetadata($referenceMetadata);
  125. $this->walker->walkObject($this->metadata, $entity, 'Default', '');
  126. // The validation of the reference's FailingConstraint in group
  127. // "Default" was launched
  128. $violations = new ConstraintViolationList();
  129. $violations->add(new ConstraintViolation(
  130. '',
  131. array(),
  132. 'Root',
  133. 'reference',
  134. $entity->reference
  135. ));
  136. $this->assertEquals($violations, $this->walker->getViolations());
  137. }
  138. public function testWalkObjectInOtherGroupTraversesNoGroupSequence()
  139. {
  140. $entity = new Entity();
  141. $this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array(
  142. 'groups' => 'First',
  143. )));
  144. $this->metadata->addGetterConstraint('lastName', new FailingConstraint(array(
  145. 'groups' => $this->metadata->getDefaultGroup(),
  146. )));
  147. $this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup()));
  148. $this->walker->walkObject($this->metadata, $entity, $this->metadata->getDefaultGroup(), '');
  149. // Only group "Second" was validated
  150. $violations = new ConstraintViolationList();
  151. $violations->add(new ConstraintViolation(
  152. '',
  153. array(),
  154. 'Root',
  155. 'lastName',
  156. ''
  157. ));
  158. $this->assertEquals($violations, $this->walker->getViolations());
  159. }
  160. public function testWalkPropertyValueValidatesConstraints()
  161. {
  162. $this->metadata->addPropertyConstraint('firstName', new ConstraintA());
  163. $this->walker->walkPropertyValue($this->metadata, 'firstName', 'value', 'Default', '');
  164. $this->assertEquals(1, count($this->walker->getViolations()));
  165. }
  166. public function testWalkCascadedPropertyValidatesReferences()
  167. {
  168. $entity = new Entity();
  169. $entityMetadata = new ClassMetadata(get_class($entity));
  170. $this->factory->addClassMetadata($entityMetadata);
  171. // add a constraint for the entity that always fails
  172. $entityMetadata->addConstraint(new FailingConstraint());
  173. // validate entity when validating the property "reference"
  174. $this->metadata->addPropertyConstraint('reference', new Valid());
  175. // invoke validation on an object
  176. $this->walker->walkPropertyValue(
  177. $this->metadata,
  178. 'reference',
  179. $entity, // object!
  180. 'Default',
  181. 'path'
  182. );
  183. $violations = new ConstraintViolationList();
  184. $violations->add(new ConstraintViolation(
  185. '',
  186. array(),
  187. 'Root',
  188. 'path',
  189. $entity
  190. ));
  191. $this->assertEquals($violations, $this->walker->getViolations());
  192. }
  193. public function testWalkCascadedPropertyValidatesArraysByDefault()
  194. {
  195. $entity = new Entity();
  196. $entityMetadata = new ClassMetadata(get_class($entity));
  197. $this->factory->addClassMetadata($entityMetadata);
  198. // add a constraint for the entity that always fails
  199. $entityMetadata->addConstraint(new FailingConstraint());
  200. // validate array when validating the property "reference"
  201. $this->metadata->addPropertyConstraint('reference', new Valid());
  202. $this->walker->walkPropertyValue(
  203. $this->metadata,
  204. 'reference',
  205. array('key' => $entity), // array!
  206. 'Default',
  207. 'path'
  208. );
  209. $violations = new ConstraintViolationList();
  210. $violations->add(new ConstraintViolation(
  211. '',
  212. array(),
  213. 'Root',
  214. 'path[key]',
  215. $entity
  216. ));
  217. $this->assertEquals($violations, $this->walker->getViolations());
  218. }
  219. public function testWalkCascadedPropertyValidatesTraversableByDefault()
  220. {
  221. $entity = new Entity();
  222. $entityMetadata = new ClassMetadata(get_class($entity));
  223. $this->factory->addClassMetadata($entityMetadata);
  224. $this->factory->addClassMetadata(new ClassMetadata('ArrayIterator'));
  225. // add a constraint for the entity that always fails
  226. $entityMetadata->addConstraint(new FailingConstraint());
  227. // validate array when validating the property "reference"
  228. $this->metadata->addPropertyConstraint('reference', new Valid());
  229. $this->walker->walkPropertyValue(
  230. $this->metadata,
  231. 'reference',
  232. new \ArrayIterator(array('key' => $entity)),
  233. 'Default',
  234. 'path'
  235. );
  236. $violations = new ConstraintViolationList();
  237. $violations->add(new ConstraintViolation(
  238. '',
  239. array(),
  240. 'Root',
  241. 'path[key]',
  242. $entity
  243. ));
  244. $this->assertEquals($violations, $this->walker->getViolations());
  245. }
  246. public function testWalkCascadedPropertyDoesNotValidateTraversableIfDisabled()
  247. {
  248. $entity = new Entity();
  249. $entityMetadata = new ClassMetadata(get_class($entity));
  250. $this->factory->addClassMetadata($entityMetadata);
  251. $this->factory->addClassMetadata(new ClassMetadata('ArrayIterator'));
  252. // add a constraint for the entity that always fails
  253. $entityMetadata->addConstraint(new FailingConstraint());
  254. // validate array when validating the property "reference"
  255. $this->metadata->addPropertyConstraint('reference', new Valid(array(
  256. 'traverse' => false,
  257. )));
  258. $this->walker->walkPropertyValue(
  259. $this->metadata,
  260. 'reference',
  261. new \ArrayIterator(array('key' => $entity)),
  262. 'Default',
  263. 'path'
  264. );
  265. $violations = new ConstraintViolationList();
  266. $this->assertEquals($violations, $this->walker->getViolations());
  267. }
  268. public function testWalkCascadedPropertyDoesNotValidateNestedScalarValues()
  269. {
  270. // validate array when validating the property "reference"
  271. $this->metadata->addPropertyConstraint('reference', new Valid());
  272. $this->walker->walkPropertyValue(
  273. $this->metadata,
  274. 'reference',
  275. array('scalar', 'values'),
  276. 'Default',
  277. 'path'
  278. );
  279. $violations = new ConstraintViolationList();
  280. $this->assertEquals($violations, $this->walker->getViolations());
  281. }
  282. public function testWalkCascadedPropertyDoesNotValidateNullValues()
  283. {
  284. $this->metadata->addPropertyConstraint('reference', new Valid());
  285. $this->walker->walkPropertyValue(
  286. $this->metadata,
  287. 'reference',
  288. null,
  289. 'Default',
  290. ''
  291. );
  292. $this->assertEquals(0, count($this->walker->getViolations()));
  293. }
  294. public function testWalkCascadedPropertyRequiresObjectOrArray()
  295. {
  296. $this->metadata->addPropertyConstraint('reference', new Valid());
  297. $this->setExpectedException('Symfony\Component\Validator\Exception\UnexpectedTypeException');
  298. $this->walker->walkPropertyValue(
  299. $this->metadata,
  300. 'reference',
  301. 'no object',
  302. 'Default',
  303. ''
  304. );
  305. }
  306. public function testWalkConstraintBuildsAViolationIfFailed()
  307. {
  308. $constraint = new ConstraintA();
  309. $this->walker->walkConstraint($constraint, 'foobar', 'Default', 'firstName.path');
  310. $violations = new ConstraintViolationList();
  311. $violations->add(new ConstraintViolation(
  312. 'message',
  313. array('param' => 'value'),
  314. 'Root',
  315. 'firstName.path',
  316. 'foobar'
  317. ));
  318. $this->assertEquals($violations, $this->walker->getViolations());
  319. }
  320. public function testWalkConstraintBuildsNoViolationIfSuccessful()
  321. {
  322. $constraint = new ConstraintA();
  323. $this->walker->walkConstraint($constraint, 'VALID', 'Default', 'firstName.path');
  324. $this->assertEquals(0, count($this->walker->getViolations()));
  325. }
  326. }