AbstractDivLayoutTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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. use Symfony\Component\Form\FormError;
  12. abstract class AbstractDivLayoutTest extends AbstractLayoutTest
  13. {
  14. public function testRow()
  15. {
  16. $form = $this->factory->createNamed('text', 'name');
  17. $form->addError(new FormError('Error!'));
  18. $view = $form->createView();
  19. $html = $this->renderRow($view);
  20. $this->assertMatchesXpath($html,
  21. '/div
  22. [
  23. ./label[@for="name"]
  24. /following-sibling::ul
  25. [./li[.="[trans]Error![/trans]"]]
  26. [count(./li)=1]
  27. /following-sibling::input[@id="name"]
  28. ]
  29. '
  30. );
  31. }
  32. public function testRowOverrideVariables()
  33. {
  34. $view = $this->factory->createNamed('text', 'name')->createView();
  35. $html = $this->renderRow($view, array('label' => 'foo&bar'));
  36. $this->assertMatchesXpath($html,
  37. '/div
  38. [
  39. ./label[@for="name"][.="[trans]foo&bar[/trans]"]
  40. /following-sibling::input[@id="name"]
  41. ]
  42. '
  43. );
  44. }
  45. public function testRepeatedRow()
  46. {
  47. $form = $this->factory->createNamed('repeated', 'name');
  48. $form->addError(new FormError('Error!'));
  49. $view = $form->createView();
  50. $html = $this->renderRow($view);
  51. $this->assertMatchesXpath($html,
  52. '/ul
  53. [./li[.="[trans]Error![/trans]"]]
  54. [count(./li)=1]
  55. /following-sibling::div
  56. [
  57. ./label[@for="name_first"]
  58. /following-sibling::input[@id="name_first"]
  59. ]
  60. /following-sibling::div
  61. [
  62. ./label[@for="name_second"]
  63. /following-sibling::input[@id="name_second"]
  64. ]
  65. '
  66. );
  67. }
  68. public function testRest()
  69. {
  70. $view = $this->factory->createNamedBuilder('form', 'name')
  71. ->add('field1', 'text')
  72. ->add('field2', 'repeated')
  73. ->add('field3', 'text')
  74. ->add('field4', 'text')
  75. ->getForm()
  76. ->createView();
  77. // Render field2 row -> does not implicitly call renderWidget because
  78. // it is a repeated field!
  79. $this->renderRow($view['field2']);
  80. // Render field3 widget
  81. $this->renderWidget($view['field3']);
  82. // Rest should only contain field1 and field4
  83. $html = $this->renderRest($view);
  84. $this->assertMatchesXpath($html,
  85. '/input
  86. [@type="hidden"]
  87. [@id="name__token"]
  88. /following-sibling::div
  89. [
  90. ./label[@for="name_field1"]
  91. /following-sibling::input[@type="text"][@id="name_field1"]
  92. ]
  93. /following-sibling::div
  94. [
  95. ./label[@for="name_field4"]
  96. /following-sibling::input[@type="text"][@id="name_field4"]
  97. ]
  98. [count(../div)=2]
  99. [count(..//label)=2]
  100. [count(..//input)=3]
  101. '
  102. );
  103. }
  104. public function testRestWithChildrenForms()
  105. {
  106. $child1 = $this->factory->createNamedBuilder('form', 'child1')
  107. ->add('field1', 'text')
  108. ->add('field2', 'text')
  109. ->getForm();
  110. $child2 = $this->factory->createNamedBuilder('form', 'child2')
  111. ->add('field1', 'text')
  112. ->add('field2', 'text')
  113. ->getForm();
  114. $view = $this->factory->createNamedBuilder('form', 'parent')
  115. ->getForm()
  116. ->add($child1)
  117. ->add($child2)
  118. ->createView();
  119. // Render child1.field1 row
  120. $this->renderRow($view['child1']['field1']);
  121. // Render child2.field2 widget (remember that widget don't render label)
  122. $this->renderWidget($view['child2']['field2']);
  123. // Rest should only contain child1.field2 and child2.field1
  124. $html = $this->renderRest($view);
  125. $this->assertMatchesXpath($html,
  126. '/input[@type="hidden"][@id="parent__token"]
  127. /following-sibling::div
  128. [
  129. ./label[not(@for)]
  130. /following-sibling::div[@id="parent_child1"]
  131. [
  132. ./div
  133. [
  134. ./label[@for="parent_child1_field2"]
  135. /following-sibling::input[@id="parent_child1_field2"]
  136. ]
  137. ]
  138. ]
  139. /following-sibling::div
  140. [
  141. ./label[not(@for)]
  142. /following-sibling::div[@id="parent_child2"]
  143. [
  144. ./div
  145. [
  146. ./label[@for="parent_child2_field1"]
  147. /following-sibling::input[@id="parent_child2_field1"]
  148. ]
  149. ]
  150. ]
  151. [count(//label)=4]
  152. [count(//input[@type="text"])=2]
  153. '
  154. );
  155. }
  156. public function testRestAndRepeatedWithRow()
  157. {
  158. $view = $this->factory->createNamedBuilder('form', 'name')
  159. ->add('first', 'text')
  160. ->add('password', 'repeated')
  161. ->getForm()
  162. ->createView();
  163. $this->renderRow($view['password']);
  164. $html = $this->renderRest($view);
  165. $this->assertMatchesXpath($html,
  166. '/input
  167. [@type="hidden"]
  168. [@id="name__token"]
  169. /following-sibling::div
  170. [
  171. ./label[@for="name_first"]
  172. /following-sibling::input[@type="text"][@id="name_first"]
  173. ]
  174. [count(.//input)=1]
  175. '
  176. );
  177. }
  178. public function testRestAndRepeatedWithRowPerField()
  179. {
  180. $view = $this->factory->createNamedBuilder('form', 'name')
  181. ->add('first', 'text')
  182. ->add('password', 'repeated')
  183. ->getForm()
  184. ->createView();
  185. $this->renderRow($view['password']['first']);
  186. $this->renderRow($view['password']['second']);
  187. $html = $this->renderRest($view);
  188. $this->assertMatchesXpath($html,
  189. '/input
  190. [@type="hidden"]
  191. [@id="name__token"]
  192. /following-sibling::div
  193. [
  194. ./label[@for="name_first"]
  195. /following-sibling::input[@type="text"][@id="name_first"]
  196. ]
  197. [count(.//input)=1]
  198. [count(.//label)=1]
  199. '
  200. );
  201. }
  202. public function testRestAndRepeatedWithWidgetPerField()
  203. {
  204. $view = $this->factory->createNamedBuilder('form', 'name')
  205. ->add('first', 'text')
  206. ->add('password', 'repeated')
  207. ->getForm()
  208. ->createView();
  209. // The password form is considered as rendered as all its childrend
  210. // are rendered
  211. $this->renderWidget($view['password']['first']);
  212. $this->renderWidget($view['password']['second']);
  213. $html = $this->renderRest($view);
  214. $this->assertMatchesXpath($html,
  215. '/input
  216. [@type="hidden"]
  217. [@id="name__token"]
  218. /following-sibling::div
  219. [
  220. ./label[@for="name_first"]
  221. /following-sibling::input[@type="text"][@id="name_first"]
  222. ]
  223. [count(//input)=2]
  224. [count(//label)=1]
  225. '
  226. );
  227. }
  228. public function testCollection()
  229. {
  230. $form = $this->factory->createNamed('collection', 'name', array('a', 'b'), array(
  231. 'type' => 'text',
  232. ));
  233. $this->assertWidgetMatchesXpath($form->createView(), array(),
  234. '/div
  235. [
  236. ./div[./input[@type="text"][@value="a"]]
  237. /following-sibling::div[./input[@type="text"][@value="b"]]
  238. ]
  239. [count(./div[./input])=2]
  240. '
  241. );
  242. }
  243. public function testCollectionRow()
  244. {
  245. $collection = $this->factory->createNamedBuilder(
  246. 'collection',
  247. 'collection',
  248. array('a', 'b'),
  249. array('type' => 'text')
  250. );
  251. $form = $this->factory->createNamedBuilder('form', 'form')
  252. ->add($collection)
  253. ->getForm();
  254. $this->assertWidgetMatchesXpath($form->createView(), array(),
  255. '/div
  256. [
  257. ./input[@type="hidden"][@id="form__token"]
  258. /following-sibling::div
  259. [
  260. ./label[not(@for)]
  261. /following-sibling::div
  262. [
  263. ./div
  264. [
  265. ./label[@for="form_collection_0"]
  266. /following-sibling::input[@type="text"][@value="a"]
  267. ]
  268. /following-sibling::div
  269. [
  270. ./label[@for="form_collection_1"]
  271. /following-sibling::input[@type="text"][@value="b"]
  272. ]
  273. ]
  274. ]
  275. ]
  276. [count(.//input)=3]
  277. '
  278. );
  279. }
  280. public function testForm()
  281. {
  282. $form = $this->factory->createNamedBuilder('form', 'name')
  283. ->add('firstName', 'text')
  284. ->add('lastName', 'text')
  285. ->getForm();
  286. $this->assertWidgetMatchesXpath($form->createView(), array(),
  287. '/div
  288. [
  289. ./input[@type="hidden"][@id="name__token"]
  290. /following-sibling::div
  291. [
  292. ./label[@for="name_firstName"]
  293. /following-sibling::input[@type="text"][@id="name_firstName"]
  294. ]
  295. /following-sibling::div
  296. [
  297. ./label[@for="name_lastName"]
  298. /following-sibling::input[@type="text"][@id="name_lastName"]
  299. ]
  300. ]
  301. [count(.//input)=3]
  302. '
  303. );
  304. }
  305. public function testRepeated()
  306. {
  307. $form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
  308. 'type' => 'text',
  309. ));
  310. $this->assertWidgetMatchesXpath($form->createView(), array(),
  311. '/div
  312. [
  313. ./div
  314. [
  315. ./label[@for="name_first"]
  316. /following-sibling::input[@type="text"][@id="name_first"]
  317. ]
  318. /following-sibling::div
  319. [
  320. ./label[@for="name_second"]
  321. /following-sibling::input[@type="text"][@id="name_second"]
  322. ]
  323. ]
  324. [count(.//input)=2]
  325. '
  326. );
  327. }
  328. public function testSearchInputName()
  329. {
  330. $form = $this->factory->createNamedBuilder('form', 'full')
  331. ->add('name', 'search')
  332. ->getForm();
  333. $this->assertWidgetMatchesXpath($form->createView(), array(),
  334. '/div
  335. [
  336. ./input[@type="hidden"][@id="full__token"]
  337. /following-sibling::div
  338. [
  339. ./label[@for="full_name"]
  340. /following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
  341. ]
  342. ]
  343. [count(//input)=2]
  344. '
  345. );
  346. }
  347. public function testLabelHasNoId()
  348. {
  349. $form = $this->factory->createNamed('text', 'name');
  350. $html = $this->renderRow($form->createView());
  351. $this->assertMatchesXpath($html,
  352. '/div
  353. [
  354. ./label[@for="name"][not(@id)]
  355. /following-sibling::input[@id="name"]
  356. ]
  357. '
  358. );
  359. }
  360. /**
  361. * @dataProvider themeBlockInheritanceProvider
  362. */
  363. public function testThemeBlockInheritance($theme)
  364. {
  365. $view = $this->factory
  366. ->createNamed('email', 'name')
  367. ->createView()
  368. ;
  369. $this->setTheme($view, $theme);
  370. $this->assertMatchesXpath(
  371. $this->renderWidget($view),
  372. '/input[@type="email"][@rel="theme"]'
  373. );
  374. }
  375. /**
  376. * @dataProvider themeInheritanceProvider
  377. */
  378. public function testThemeInheritance($parentTheme, $childTheme)
  379. {
  380. $child = $this->factory->createNamedBuilder('form', 'child')
  381. ->add('field', 'text')
  382. ->getForm();
  383. $view = $this->factory->createNamedBuilder('form', 'parent')
  384. ->add('field', 'text')
  385. ->getForm()
  386. ->add($child)
  387. ->createView()
  388. ;
  389. $this->setTheme($view, $parentTheme);
  390. $this->setTheme($view['child'], $childTheme);
  391. $this->assertWidgetMatchesXpath($view, array(),
  392. '/div
  393. [
  394. ./input[@type="hidden"]
  395. /following-sibling::div
  396. [
  397. ./label[.="parent"]
  398. /following-sibling::input[@type="text"]
  399. ]
  400. /following-sibling::div
  401. [
  402. ./label
  403. /following-sibling::div
  404. [
  405. ./div
  406. [
  407. ./label[.="child"]
  408. /following-sibling::input[@type="text"]
  409. ]
  410. ]
  411. ]
  412. ]
  413. '
  414. );
  415. }
  416. }