PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php

https://bitbucket.org/vvanuytven/php_auto
PHP | 509 lines | 432 code | 48 blank | 29 comment | 0 complexity | d9749c5149cba7e97130254f276cf987 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\Component\Form\Tests;
  11. use Symfony\Component\Form\FormError;
  12. abstract class AbstractTableLayoutTest extends AbstractLayoutTest
  13. {
  14. public function testRow()
  15. {
  16. $form = $this->factory->createNamed('name', 'text');
  17. $form->addError(new FormError('[trans]Error![/trans]'));
  18. $view = $form->createView();
  19. $html = $this->renderRow($view);
  20. $this->assertMatchesXpath($html,
  21. '/tr
  22. [
  23. ./td
  24. [./label[@for="name"]]
  25. /following-sibling::td
  26. [
  27. ./ul
  28. [./li[.="[trans]Error![/trans]"]]
  29. [count(./li)=1]
  30. /following-sibling::input[@id="name"]
  31. ]
  32. ]
  33. '
  34. );
  35. }
  36. public function testLabelIsNotRenderedWhenSetToFalse()
  37. {
  38. $form = $this->factory->createNamed('name', 'text', null, array(
  39. 'label' => false
  40. ));
  41. $html = $this->renderRow($form->createView());
  42. $this->assertMatchesXpath($html,
  43. '/tr
  44. [
  45. ./td
  46. [count(//label)=0]
  47. /following-sibling::td
  48. [./input[@id="name"]]
  49. ]
  50. '
  51. );
  52. }
  53. public function testRepeatedRow()
  54. {
  55. $form = $this->factory->createNamed('name', 'repeated');
  56. $html = $this->renderRow($form->createView());
  57. $this->assertMatchesXpath($html,
  58. '/tr
  59. [
  60. ./td
  61. [./label[@for="name_first"]]
  62. /following-sibling::td
  63. [./input[@id="name_first"]]
  64. ]
  65. /following-sibling::tr
  66. [
  67. ./td
  68. [./label[@for="name_second"]]
  69. /following-sibling::td
  70. [./input[@id="name_second"]]
  71. ]
  72. /following-sibling::tr[@style="display: none"]
  73. [./td[@colspan="2"]/input
  74. [@type="hidden"]
  75. [@id="name__token"]
  76. ]
  77. [count(../tr)=3]
  78. '
  79. );
  80. }
  81. public function testRepeatedRowWithErrors()
  82. {
  83. $form = $this->factory->createNamed('name', 'repeated');
  84. $form->addError(new FormError('[trans]Error![/trans]'));
  85. $view = $form->createView();
  86. $html = $this->renderRow($view);
  87. // The errors of the form are not rendered by intention!
  88. // In practice, repeated fields cannot have errors as all errors
  89. // on them are mapped to the first child.
  90. // (see RepeatedTypeValidatorExtension)
  91. $this->assertMatchesXpath($html,
  92. '/tr
  93. [
  94. ./td
  95. [./label[@for="name_first"]]
  96. /following-sibling::td
  97. [./input[@id="name_first"]]
  98. ]
  99. /following-sibling::tr
  100. [
  101. ./td
  102. [./label[@for="name_second"]]
  103. /following-sibling::td
  104. [./input[@id="name_second"]]
  105. ]
  106. /following-sibling::tr[@style="display: none"]
  107. [./td[@colspan="2"]/input
  108. [@type="hidden"]
  109. [@id="name__token"]
  110. ]
  111. [count(../tr)=3]
  112. '
  113. );
  114. }
  115. public function testButtonRow()
  116. {
  117. $form = $this->factory->createNamed('name', 'button');
  118. $view = $form->createView();
  119. $html = $this->renderRow($view);
  120. $this->assertMatchesXpath($html,
  121. '/tr
  122. [
  123. ./td
  124. [.=""]
  125. /following-sibling::td
  126. [./button[@type="button"][@name="name"]]
  127. ]
  128. [count(//label)=0]
  129. '
  130. );
  131. }
  132. public function testRest()
  133. {
  134. $view = $this->factory->createNamedBuilder('name', 'form')
  135. ->add('field1', 'text')
  136. ->add('field2', 'repeated')
  137. ->add('field3', 'text')
  138. ->add('field4', 'text')
  139. ->getForm()
  140. ->createView();
  141. // Render field2 row -> does not implicitly call renderWidget because
  142. // it is a repeated field!
  143. $this->renderRow($view['field2']);
  144. // Render field3 widget
  145. $this->renderWidget($view['field3']);
  146. // Rest should only contain field1 and field4
  147. $html = $this->renderRest($view);
  148. $this->assertMatchesXpath($html,
  149. '/tr
  150. [
  151. ./td
  152. [./label[@for="name_field1"]]
  153. /following-sibling::td
  154. [./input[@id="name_field1"]]
  155. ]
  156. /following-sibling::tr
  157. [
  158. ./td
  159. [./label[@for="name_field4"]]
  160. /following-sibling::td
  161. [./input[@id="name_field4"]]
  162. ]
  163. [count(../tr)=3]
  164. [count(..//label)=2]
  165. [count(..//input)=3]
  166. /following-sibling::tr[@style="display: none"]
  167. [./td[@colspan="2"]/input
  168. [@type="hidden"]
  169. [@id="name__token"]
  170. ]
  171. '
  172. );
  173. }
  174. public function testCollection()
  175. {
  176. $form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
  177. 'type' => 'text',
  178. ));
  179. $this->assertWidgetMatchesXpath($form->createView(), array(),
  180. '/table
  181. [
  182. ./tr[./td/input[@type="text"][@value="a"]]
  183. /following-sibling::tr[./td/input[@type="text"][@value="b"]]
  184. /following-sibling::tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]
  185. ]
  186. [count(./tr[./td/input])=3]
  187. '
  188. );
  189. }
  190. public function testEmptyCollection()
  191. {
  192. $form = $this->factory->createNamed('name', 'collection', array(), array(
  193. 'type' => 'text',
  194. ));
  195. $this->assertWidgetMatchesXpath($form->createView(), array(),
  196. '/table
  197. [./tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]]
  198. [count(./tr[./td/input])=1]
  199. '
  200. );
  201. }
  202. public function testForm()
  203. {
  204. $view = $this->factory->createNamedBuilder('name', 'form')
  205. ->setMethod('PUT')
  206. ->setAction('http://example.com')
  207. ->add('firstName', 'text')
  208. ->add('lastName', 'text')
  209. ->getForm()
  210. ->createView();
  211. $html = $this->renderForm($view, array(
  212. 'id' => 'my&id',
  213. 'attr' => array('class' => 'my&class'),
  214. ));
  215. $this->assertMatchesXpath($html,
  216. '/form
  217. [
  218. ./input[@type="hidden"][@name="_method"][@value="PUT"]
  219. /following-sibling::table
  220. [
  221. ./tr
  222. [
  223. ./td
  224. [./label[@for="name_firstName"]]
  225. /following-sibling::td
  226. [./input[@id="name_firstName"]]
  227. ]
  228. /following-sibling::tr
  229. [
  230. ./td
  231. [./label[@for="name_lastName"]]
  232. /following-sibling::td
  233. [./input[@id="name_lastName"]]
  234. ]
  235. /following-sibling::tr[@style="display: none"]
  236. [./td[@colspan="2"]/input
  237. [@type="hidden"]
  238. [@id="name__token"]
  239. ]
  240. ]
  241. [count(.//input)=3]
  242. [@id="my&id"]
  243. [@class="my&class"]
  244. ]
  245. [@method="post"]
  246. [@action="http://example.com"]
  247. [@class="my&class"]
  248. '
  249. );
  250. }
  251. public function testFormWidget()
  252. {
  253. $view = $this->factory->createNamedBuilder('name', 'form')
  254. ->add('firstName', 'text')
  255. ->add('lastName', 'text')
  256. ->getForm()
  257. ->createView();
  258. $this->assertWidgetMatchesXpath($view, array(),
  259. '/table
  260. [
  261. ./tr
  262. [
  263. ./td
  264. [./label[@for="name_firstName"]]
  265. /following-sibling::td
  266. [./input[@id="name_firstName"]]
  267. ]
  268. /following-sibling::tr
  269. [
  270. ./td
  271. [./label[@for="name_lastName"]]
  272. /following-sibling::td
  273. [./input[@id="name_lastName"]]
  274. ]
  275. /following-sibling::tr[@style="display: none"]
  276. [./td[@colspan="2"]/input
  277. [@type="hidden"]
  278. [@id="name__token"]
  279. ]
  280. ]
  281. [count(.//input)=3]
  282. '
  283. );
  284. }
  285. // https://github.com/symfony/symfony/issues/2308
  286. public function testNestedFormError()
  287. {
  288. $form = $this->factory->createNamedBuilder('name', 'form')
  289. ->add($this->factory
  290. ->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
  291. ->add('grandChild', 'form')
  292. )
  293. ->getForm();
  294. $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
  295. $this->assertWidgetMatchesXpath($form->createView(), array(),
  296. '/table
  297. [
  298. ./tr/td/ul[./li[.="[trans]Error![/trans]"]]
  299. /following-sibling::table[@id="name_child"]
  300. ]
  301. [count(.//li[.="[trans]Error![/trans]"])=1]
  302. '
  303. );
  304. }
  305. public function testCsrf()
  306. {
  307. $this->csrfProvider->expects($this->any())
  308. ->method('generateCsrfToken')
  309. ->will($this->returnValue('foo&bar'));
  310. $form = $this->factory->createNamedBuilder('name', 'form')
  311. ->add($this->factory
  312. // No CSRF protection on nested forms
  313. ->createNamedBuilder('child', 'form')
  314. ->add($this->factory->createNamedBuilder('grandchild', 'text'))
  315. )
  316. ->getForm();
  317. $this->assertWidgetMatchesXpath($form->createView(), array(),
  318. '/table
  319. [
  320. ./tr[@style="display: none"]
  321. [./td[@colspan="2"]/input
  322. [@type="hidden"]
  323. [@id="name__token"]
  324. ]
  325. ]
  326. [count(.//input[@type="hidden"])=1]
  327. '
  328. );
  329. }
  330. public function testRepeated()
  331. {
  332. $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
  333. 'type' => 'text',
  334. ));
  335. $this->assertWidgetMatchesXpath($form->createView(), array(),
  336. '/table
  337. [
  338. ./tr
  339. [
  340. ./td
  341. [./label[@for="name_first"]]
  342. /following-sibling::td
  343. [./input[@type="text"][@id="name_first"]]
  344. ]
  345. /following-sibling::tr
  346. [
  347. ./td
  348. [./label[@for="name_second"]]
  349. /following-sibling::td
  350. [./input[@type="text"][@id="name_second"]]
  351. ]
  352. /following-sibling::tr[@style="display: none"]
  353. [./td[@colspan="2"]/input
  354. [@type="hidden"]
  355. [@id="name__token"]
  356. ]
  357. ]
  358. [count(.//input)=3]
  359. '
  360. );
  361. }
  362. public function testRepeatedWithCustomOptions()
  363. {
  364. $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
  365. 'type' => 'password',
  366. 'first_options' => array('label' => 'Test', 'required' => false),
  367. 'second_options' => array('label' => 'Test2')
  368. ));
  369. $this->assertWidgetMatchesXpath($form->createView(), array(),
  370. '/table
  371. [
  372. ./tr
  373. [
  374. ./td
  375. [./label[@for="name_first"][.="[trans]Test[/trans]"]]
  376. /following-sibling::td
  377. [./input[@type="password"][@id="name_first"][@required="required"]]
  378. ]
  379. /following-sibling::tr
  380. [
  381. ./td
  382. [./label[@for="name_second"][.="[trans]Test2[/trans]"]]
  383. /following-sibling::td
  384. [./input[@type="password"][@id="name_second"][@required="required"]]
  385. ]
  386. /following-sibling::tr[@style="display: none"]
  387. [./td[@colspan="2"]/input
  388. [@type="hidden"]
  389. [@id="name__token"]
  390. ]
  391. ]
  392. [count(.//input)=3]
  393. '
  394. );
  395. }
  396. /**
  397. * The block "_name_child_label" should be overridden in the theme of the
  398. * implemented driver.
  399. */
  400. public function testCollectionRowWithCustomBlock()
  401. {
  402. $collection = array('one', 'two', 'three');
  403. $form = $this->factory->createNamedBuilder('name', 'collection', $collection)
  404. ->getForm();
  405. $this->assertWidgetMatchesXpath($form->createView(), array(),
  406. '/table
  407. [
  408. ./tr[./td/label[.="Custom label: [trans]0[/trans]"]]
  409. /following-sibling::tr[./td/label[.="Custom label: [trans]1[/trans]"]]
  410. /following-sibling::tr[./td/label[.="Custom label: [trans]2[/trans]"]]
  411. ]
  412. '
  413. );
  414. }
  415. public function testFormEndWithRest()
  416. {
  417. $view = $this->factory->createNamedBuilder('name', 'form')
  418. ->add('field1', 'text')
  419. ->add('field2', 'text')
  420. ->getForm()
  421. ->createView();
  422. $this->renderWidget($view['field1']);
  423. // Rest should only contain field2
  424. $html = $this->renderEnd($view);
  425. // Insert the start tag, the end tag should be rendered by the helper
  426. // Unfortunately this is not valid HTML, because the surrounding table
  427. // tag is missing. If someone renders a form with table layout
  428. // manually, she should call form_rest() explicitly within the <table>
  429. // tag.
  430. $this->assertMatchesXpath('<form>' . $html,
  431. '/form
  432. [
  433. ./tr
  434. [
  435. ./td
  436. [./label[@for="name_field2"]]
  437. /following-sibling::td
  438. [./input[@id="name_field2"]]
  439. ]
  440. /following-sibling::tr[@style="display: none"]
  441. [./td[@colspan="2"]/input
  442. [@type="hidden"]
  443. [@id="name__token"]
  444. ]
  445. ]
  446. '
  447. );
  448. }
  449. public function testFormEndWithoutRest()
  450. {
  451. $view = $this->factory->createNamedBuilder('name', 'form')
  452. ->add('field1', 'text')
  453. ->add('field2', 'text')
  454. ->getForm()
  455. ->createView();
  456. $this->renderWidget($view['field1']);
  457. // Rest should only contain field2, but isn't rendered
  458. $html = $this->renderEnd($view, array('render_rest' => false));
  459. $this->assertEquals('</form>', $html);
  460. }
  461. }