FieldTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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;
  11. require_once __DIR__ . '/TestCase.php';
  12. require_once __DIR__ . '/Fixtures/Author.php';
  13. require_once __DIR__ . '/Fixtures/FixedDataTransformer.php';
  14. require_once __DIR__ . '/Fixtures/FixedFilterListener.php';
  15. use Symfony\Component\Form\DataTransformer\DataTransformerInterface;
  16. use Symfony\Component\Form\PropertyPath;
  17. use Symfony\Component\Form\FormError;
  18. use Symfony\Component\Form\Form;
  19. use Symfony\Component\Form\DataTransformer\TransformationFailedException;
  20. use Symfony\Tests\Component\Form\Fixtures\Author;
  21. use Symfony\Tests\Component\Form\Fixtures\FixedDataTransformer;
  22. use Symfony\Tests\Component\Form\Fixtures\FixedFilterListener;
  23. class FieldTest extends TestCase
  24. {
  25. protected $field;
  26. protected function setUp()
  27. {
  28. parent::setUp();
  29. $this->field = $this->factory->create('field', 'title');
  30. }
  31. public function testGetPropertyPath_defaultPath()
  32. {
  33. $field = $this->factory->create('field', 'title');
  34. $this->assertEquals(new PropertyPath('title'), $field->getAttribute('property_path'));
  35. }
  36. public function testGetPropertyPath_pathIsZero()
  37. {
  38. $field = $this->factory->create('field', 'title', array('property_path' => '0'));
  39. $this->assertEquals(new PropertyPath('0'), $field->getAttribute('property_path'));
  40. }
  41. public function testGetPropertyPath_pathIsEmpty()
  42. {
  43. $field = $this->factory->create('field', 'title', array('property_path' => ''));
  44. $this->assertEquals(null, $field->getAttribute('property_path'));
  45. }
  46. public function testGetPropertyPath_pathIsNull()
  47. {
  48. $field = $this->factory->create('field', 'title', array('property_path' => null));
  49. $this->assertEquals(null, $field->getAttribute('property_path'));
  50. }
  51. public function testPassRequiredAsOption()
  52. {
  53. $field = $this->factory->create('field', 'title', array('required' => false));
  54. $this->assertFalse($field->isRequired());
  55. $field = $this->factory->create('field', 'title', array('required' => true));
  56. $this->assertTrue($field->isRequired());
  57. }
  58. public function testPassReadOnlyAsOption()
  59. {
  60. $field = $this->factory->create('field', 'title', array('read_only' => false));
  61. $this->assertFalse($field->isReadOnly());
  62. $field = $this->factory->create('field', 'title', array('read_only' => true));
  63. $this->assertTrue($field->isReadOnly());
  64. }
  65. public function testFieldIsReadOnlyIfParentIsReadOnly()
  66. {
  67. $field = $this->factory->create('field', 'title', array('read_only' => false));
  68. $field->setParent($this->factory->create('field', 'title', array('read_only' => true)));
  69. $this->assertTrue($field->isReadOnly());
  70. }
  71. public function testFieldWithNoErrorsIsValid()
  72. {
  73. $this->field->bind('data');
  74. $this->assertTrue($this->field->isValid());
  75. }
  76. public function testFieldWithErrorsIsInvalid()
  77. {
  78. $this->field->bind('data');
  79. $this->field->addError(new FormError('Some error'));
  80. $this->assertFalse($this->field->isValid());
  81. }
  82. public function testSubmitResetsErrors()
  83. {
  84. $this->field->addError(new FormError('Some error'));
  85. $this->field->bind('data');
  86. $this->assertTrue($this->field->isValid());
  87. }
  88. public function testUnboundFieldIsInvalid()
  89. {
  90. $this->assertFalse($this->field->isValid());
  91. }
  92. public function testIsRequiredReturnsOwnValueIfNoParent()
  93. {
  94. $field = $this->factory->create('field', 'test', array(
  95. 'required' => true,
  96. ));
  97. $this->assertTrue($field->isRequired());
  98. $field = $this->factory->create('field', 'test', array(
  99. 'required' => false,
  100. ));
  101. $this->assertFalse($field->isRequired());
  102. }
  103. public function testIsRequiredReturnsOwnValueIfParentIsRequired()
  104. {
  105. $group = $this->createMockGroup();
  106. $group->expects($this->any())
  107. ->method('isRequired')
  108. ->will($this->returnValue(true));
  109. $field = $this->factory->create('field', 'test', array(
  110. 'required' => true,
  111. ));
  112. $field->setParent($group);
  113. $this->assertTrue($field->isRequired());
  114. $field = $this->factory->create('field', 'test', array(
  115. 'required' => false,
  116. ));
  117. $field->setParent($group);
  118. $this->assertFalse($field->isRequired());
  119. }
  120. public function testIsRequiredReturnsFalseIfParentIsNotRequired()
  121. {
  122. $group = $this->createMockGroup();
  123. $group->expects($this->any())
  124. ->method('isRequired')
  125. ->will($this->returnValue(false));
  126. $field = $this->factory->create('field', 'test', array(
  127. 'required' => true,
  128. ));
  129. $field->setParent($group);
  130. $this->assertFalse($field->isRequired());
  131. }
  132. public function testIsBound()
  133. {
  134. $this->assertFalse($this->field->isBound());
  135. $this->field->bind('symfony');
  136. $this->assertTrue($this->field->isBound());
  137. }
  138. public function testDefaultDataIsTransformedCorrectly()
  139. {
  140. $field = $this->factory->create('field', 'name');
  141. $this->assertEquals(null, $this->field->getData());
  142. $this->assertEquals('', $this->field->getClientData());
  143. }
  144. public function testDataIsTransformedCorrectlyIfNull_noDataTransformer()
  145. {
  146. $this->field->setData(null);
  147. $this->assertSame(null, $this->field->getData());
  148. $this->assertSame('', $this->field->getClientData());
  149. }
  150. public function testDataIsTransformedCorrectlyIfNotNull_noDataTransformer()
  151. {
  152. $this->field->setData(123);
  153. // The values are synchronized
  154. // Without value transformer, the field can't know that the data
  155. // should be casted to an integer when the field is bound
  156. // Even without binding, the data will thus be a string
  157. $this->assertSame('123', $this->field->getData());
  158. $this->assertSame('123', $this->field->getClientData());
  159. }
  160. public function testBoundDataIsTransformedCorrectly()
  161. {
  162. $filter = new FixedFilterListener(array(
  163. 'filterBoundClientData' => array(
  164. // 1. The value is converted to a string and passed to the
  165. // first filter
  166. '0' => 'filter1[0]',
  167. ),
  168. 'filterBoundNormData' => array(
  169. // 3. The normalized value is passed to the second filter
  170. 'norm[filter1[0]]' => 'filter2[norm[filter1[0]]]',
  171. ),
  172. ));
  173. $clientTransformer = new FixedDataTransformer(array(
  174. // 0. Empty initialization
  175. null => null,
  176. // 2. The filtered value is normalized
  177. 'norm[filter1[0]]' => 'filter1[0]',
  178. // 4a. The filtered normalized value is converted to client
  179. // representation
  180. 'filter2[norm[filter1[0]]]' => 'client[filter2[norm[filter1[0]]]]',
  181. ));
  182. $normTransformer = new FixedDataTransformer(array(
  183. // 0. Empty initialization
  184. null => null,
  185. // 4b. The filtered normalized value is converted to app
  186. // representation
  187. 'app[filter2[norm[filter1[0]]]]' => 'filter2[norm[filter1[0]]]',
  188. ));
  189. $this->builder->addEventSubscriber($filter);
  190. $this->builder->setClientTransformer($clientTransformer);
  191. $this->builder->setNormTransformer($normTransformer);
  192. $field = $this->builder->getForm();
  193. $field->bind(0);
  194. $this->assertEquals('app[filter2[norm[filter1[0]]]]', $field->getData());
  195. $this->assertEquals('filter2[norm[filter1[0]]]', $field->getNormData());
  196. $this->assertEquals('client[filter2[norm[filter1[0]]]]', $field->getClientData());
  197. }
  198. public function testBoundDataIsTransformedCorrectlyIfEmpty_noDataTransformer()
  199. {
  200. $this->field->bind('');
  201. $this->assertSame(null, $this->field->getData());
  202. $this->assertEquals('', $this->field->getClientData());
  203. }
  204. public function testSetDataIsTransformedCorrectly()
  205. {
  206. $normTransformer = new FixedDataTransformer(array(
  207. null => '',
  208. 0 => 'norm[0]',
  209. ));
  210. $clientTransformer = new FixedDataTransformer(array(
  211. '' => '',
  212. 'norm[0]' => 'transform[norm[0]]',
  213. ));
  214. $builder = $this->factory->createBuilder('field', 'title');
  215. $builder->setNormTransformer($normTransformer);
  216. $builder->setClientTransformer($clientTransformer);
  217. $field = $builder->getForm();
  218. $field->setData(0);
  219. $this->assertEquals(0, $field->getData());
  220. $this->assertEquals('norm[0]', $field->getNormData());
  221. $this->assertEquals('transform[norm[0]]', $field->getClientData());
  222. }
  223. public function testBoundDataIsTrimmedBeforeTransforming()
  224. {
  225. $clientTransformer = new FixedDataTransformer(array(
  226. null => '',
  227. 'reverse[a]' => 'a',
  228. ));
  229. $builder = $this->factory->createBuilder('field', 'title');
  230. $builder->setClientTransformer($clientTransformer);
  231. $field = $builder->getForm();
  232. $field->bind(' a ');
  233. $this->assertEquals('a', $field->getClientData());
  234. $this->assertEquals('reverse[a]', $field->getData());
  235. }
  236. public function testBoundDataIsNotTrimmedBeforeTransformingIfReadOnly()
  237. {
  238. $clientTransformer = new FixedDataTransformer(array(
  239. null => '',
  240. 'reverse[ a ]' => ' a ',
  241. ));
  242. $builder = $this->factory->createBuilder('field', 'title', array(
  243. 'trim' => false,
  244. ));
  245. $builder->setClientTransformer($clientTransformer);
  246. $field = $builder->getForm();
  247. $field->bind(' a ');
  248. $this->assertEquals(' a ', $field->getClientData());
  249. $this->assertEquals('reverse[ a ]', $field->getData());
  250. }
  251. public function testIsTransformationSuccessfulReturnsTrueIfReverseTransformSucceeded()
  252. {
  253. $field = $this->factory->create('field', 'title', array(
  254. 'trim' => false,
  255. ));
  256. $field->bind('a');
  257. $this->assertEquals('a', $field->getClientData());
  258. $this->assertTrue($field->isTransformationSuccessful());
  259. }
  260. public function testIsTransformationSuccessfulReturnsFalseIfReverseTransformThrowsException()
  261. {
  262. // The value is passed to the value transformer
  263. $clientTransformer = $this->createMockTransformer();
  264. $builder = $this->factory->createBuilder('field', 'title', array(
  265. 'trim' => false,
  266. ));
  267. $builder->setClientTransformer($clientTransformer);
  268. $field = $builder->getForm();
  269. $clientTransformer->expects($this->once())
  270. ->method('reverseTransform')
  271. ->will($this->throwException(new TransformationFailedException()));
  272. $field->bind('a');
  273. $this->assertEquals('a', $field->getClientData());
  274. $this->assertFalse($field->isTransformationSuccessful());
  275. }
  276. public function testGetRootReturnsRootOfParentIfSet()
  277. {
  278. $parent = $this->createMockGroup();
  279. $parent->expects($this->any())
  280. ->method('getRoot')
  281. ->will($this->returnValue('ROOT'));
  282. $this->field->setParent($parent);
  283. $this->assertEquals('ROOT', $this->field->getRoot());
  284. }
  285. public function testGetRootReturnsFieldIfNoParent()
  286. {
  287. $this->assertEquals($this->field, $this->field->getRoot());
  288. }
  289. public function testIsEmptyReturnsTrueIfNull()
  290. {
  291. $this->field->setData(null);
  292. $this->assertTrue($this->field->isEmpty());
  293. }
  294. public function testIsEmptyReturnsTrueIfEmptyString()
  295. {
  296. $this->field->setData('');
  297. $this->assertTrue($this->field->isEmpty());
  298. }
  299. public function testIsEmptyReturnsFalseIfZero()
  300. {
  301. $this->field->setData(0);
  302. $this->assertFalse($this->field->isEmpty());
  303. }
  304. protected function createMockTransformer()
  305. {
  306. return $this->getMock('Symfony\Component\Form\DataTransformer\DataTransformerInterface', array(), array(), '', false, false);
  307. }
  308. protected function createMockTransformerTransformingTo($value)
  309. {
  310. $clientTransformer = $this->createMockTransformer();
  311. $clientTransformer->expects($this->any())
  312. ->method('reverseTransform')
  313. ->will($this->returnValue($value));
  314. return $clientTransformer;
  315. }
  316. protected function createMockGroup()
  317. {
  318. return $this->getMock(
  319. 'Symfony\Component\Form\Form',
  320. array(),
  321. array(),
  322. '',
  323. false // don't call constructor
  324. );
  325. }
  326. protected function createMockGroupWithName($name)
  327. {
  328. $group = $this->createMockGroup();
  329. $group->expects($this->any())
  330. ->method('getName')
  331. ->will($this->returnValue($name));
  332. return $group;
  333. }
  334. protected function createMockGroupWithId($id)
  335. {
  336. $group = $this->createMockGroup();
  337. $group->expects($this->any())
  338. ->method('getId')
  339. ->will($this->returnValue($id));
  340. return $group;
  341. }
  342. }