SonataAdminExtensionTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <?php
  2. /*
  3. * This file is part of the Sonata package.
  4. *
  5. * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  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 Sonata\AdminBundle\Tests\Twig\Extension;
  11. use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
  12. use Sonata\AdminBundle\Admin\Pool;
  13. use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
  14. use Symfony\Bridge\Twig\Extension\TranslationExtension;
  15. use Symfony\Component\Translation\Translator;
  16. use Symfony\Component\Translation\MessageSelector;
  17. use Symfony\Component\Translation\Loader\XliffFileLoader;
  18. use Symfony\Component\Routing\Generator\UrlGenerator;
  19. use Symfony\Component\Routing\Loader\XmlFileLoader;
  20. use Symfony\Component\Config\FileLocator;
  21. use Symfony\Bridge\Twig\Extension\RoutingExtension;
  22. use Symfony\Component\Routing\RequestContext;
  23. use Sonata\AdminBundle\Exception\NoValueException;
  24. /**
  25. * Test for SonataAdminExtension
  26. *
  27. * @author Andrej Hudec <pulzarraider@gmail.com>
  28. */
  29. class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
  30. {
  31. /**
  32. * @var SonataAdminExtension
  33. */
  34. private $twigExtension;
  35. public function setUp()
  36. {
  37. date_default_timezone_set('Europe/London');
  38. $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
  39. $pool = new Pool($container, '', '');
  40. $this->twigExtension = new SonataAdminExtension($pool);
  41. $loader = new StubFilesystemLoader(array(
  42. __DIR__.'/../../../Resources/views/CRUD',
  43. ));
  44. $environment = new \Twig_Environment($loader, array('strict_variables' => true, 'cache' => false, 'autoescape' => true, 'optimizations' => 0));
  45. $environment->addExtension($this->twigExtension);
  46. //translation extension
  47. $translator = new Translator('en', new MessageSelector());
  48. $translator->addLoader('xlf', new XliffFileLoader());
  49. $translator->addResource('xlf', __DIR__.'/../../../Resources/translations/SonataAdminBundle.en.xliff', 'en', 'SonataAdminBundle');
  50. $environment->addExtension(new TranslationExtension($translator));
  51. //routing extension
  52. $xmlFileLoader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../../../Resources/config/routing')));
  53. $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
  54. $requestContext = new RequestContext();
  55. $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
  56. $environment->addExtension(new RoutingExtension($urlGenerator));
  57. $this->twigExtension->initRuntime($environment);
  58. }
  59. public function testSlugify()
  60. {
  61. $this->assertEquals($this->twigExtension->slugify('test'), 'test');
  62. $this->assertEquals($this->twigExtension->slugify('S§!@@#$#$alut'), 's-alut');
  63. $this->assertEquals($this->twigExtension->slugify('Symfony2'), 'symfony2');
  64. $this->assertEquals($this->twigExtension->slugify('test'), 'test');
  65. $this->assertEquals($this->twigExtension->slugify('c\'est bientôt l\'été'), 'c-est-bientot-l-ete');
  66. $this->assertEquals($this->twigExtension->slugify(urldecode('%2Fc\'est+bientôt+l\'été')), 'c-est-bientot-l-ete');
  67. }
  68. /**
  69. * @dataProvider getRenderListElementTests
  70. */
  71. public function testRenderListElement($expected, $type, $value, array $options)
  72. {
  73. $object = new \stdClass();
  74. $admin = $this->getMock('Sonata\AdminBundle\Admin\AdminInterface');
  75. $admin->expects($this->any())
  76. ->method('getTemplate')
  77. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_field.html.twig'));
  78. $admin->expects($this->any())
  79. ->method('isGranted')
  80. ->will($this->returnValue(true));
  81. $admin->expects($this->any())
  82. ->method('getCode')
  83. ->with($this->equalTo($object))
  84. ->will($this->returnValue('xyz'));
  85. $admin->expects($this->any())
  86. ->method('id')
  87. ->with($this->equalTo($object))
  88. ->will($this->returnValue(12345));
  89. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  90. $fieldDescription->expects($this->any())
  91. ->method('getName')
  92. ->will($this->returnValue('fd_name'));
  93. $fieldDescription->expects($this->any())
  94. ->method('getAdmin')
  95. ->will($this->returnValue($admin));
  96. $fieldDescription->expects($this->any())
  97. ->method('getValue')
  98. ->will($this->returnValue($value));
  99. $fieldDescription->expects($this->any())
  100. ->method('getType')
  101. ->will($this->returnValue($type));
  102. $fieldDescription->expects($this->any())
  103. ->method('getOptions')
  104. ->will($this->returnValue($options));
  105. $fieldDescription->expects($this->any())
  106. ->method('getTemplate')
  107. ->will($this->returnCallback(function() use ($type) {
  108. switch ($type) {
  109. case 'string':
  110. return 'SonataAdminBundle:CRUD:list_string.html.twig';
  111. case 'boolean':
  112. return 'SonataAdminBundle:CRUD:list_boolean.html.twig';
  113. case 'datetime':
  114. return 'SonataAdminBundle:CRUD:list_datetime.html.twig';
  115. case 'date':
  116. return 'SonataAdminBundle:CRUD:list_date.html.twig';
  117. case 'time':
  118. return 'SonataAdminBundle:CRUD:list_time.html.twig';
  119. case 'currency':
  120. return 'SonataAdminBundle:CRUD:list_currency.html.twig';
  121. case 'percent':
  122. return 'SonataAdminBundle:CRUD:list_percent.html.twig';
  123. case 'array':
  124. return 'SonataAdminBundle:CRUD:list_array.html.twig';
  125. case 'trans':
  126. return 'SonataAdminBundle:CRUD:list_trans.html.twig';
  127. default:
  128. return false;
  129. }
  130. }));
  131. $this->assertEquals($expected, trim(preg_replace('/\s+/', ' ', $this->twigExtension->renderListElement($object, $fieldDescription))));
  132. }
  133. public function getRenderListElementTests()
  134. {
  135. return array(
  136. array('<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>', 'string', 'Example', array()),
  137. array('<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>', 'string', null, array()),
  138. array('<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>', 'text', 'Example', array()),
  139. array('<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>', 'text', null, array()),
  140. array('<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>', 'textarea', 'Example', array()),
  141. array('<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>', 'textarea', null, array()),
  142. array('<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> December 24, 2013 10:11 </td>', 'datetime', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  143. array('<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>', 'datetime', null, array()),
  144. array('<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> 24.12.2013 10:11:12 </td>', 'datetime', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array('format'=>'d.m.Y H:i:s')),
  145. array('<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>', 'datetime', null, array('format'=>'d.m.Y H:i:s')),
  146. array('<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> December 24, 2013 </td>', 'date', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  147. array('<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>', 'date', null, array()),
  148. array('<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> 24.12.2013 </td>', 'date', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array('format'=>'d.m.Y')),
  149. array('<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>', 'date', null, array('format'=>'d.m.Y')),
  150. array('<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> 10:11:12 </td>', 'time', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  151. array('<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>', 'time', null, array()),
  152. array('<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>', 'number', 10.746135, array()),
  153. array('<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>', 'number', null, array()),
  154. array('<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>', 'integer', 5678, array()),
  155. array('<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>', 'integer', null, array()),
  156. array('<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>', 'percent', 10.746135, array()),
  157. array('<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>', 'percent', null, array()),
  158. array('<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>', 'currency', 10.746135, array('currency' => 'EUR')),
  159. array('<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>', 'currency', null, array('currency' => 'EUR')),
  160. array('<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>', 'currency', 51.23456, array('currency' => 'GBP')),
  161. array('<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>', 'currency', null, array('currency' => 'GBP')),
  162. array('<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> [1 => First] [2 => Second] </td>', 'array', array(1 => 'First', 2 => 'Second'), array('safe' => false)),
  163. array('<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>', 'array', null, array('safe' => false)),
  164. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <i class="icon-ok-circle"></i>&nbsp;yes </td>', 'boolean', true, array('editable'=>false)),
  165. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <i class="icon-ban-circle"></i>&nbsp;no </td>', 'boolean', false, array('editable'=>false)),
  166. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <i class="icon-ban-circle"></i>&nbsp;no </td>', 'boolean', null, array('editable'=>false)),
  167. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <a href="http://localhost/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;value=0&amp;code=xyz" class="sonata-ba-action sonata-ba-edit-inline"><i class="icon-ok-circle"></i>&nbsp;yes</a> </td>', 'boolean', true, array('editable'=>true)),
  168. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <a href="http://localhost/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;value=1&amp;code=xyz" class="sonata-ba-action sonata-ba-edit-inline"><i class="icon-ban-circle"></i>&nbsp;no</a> </td>', 'boolean', false, array('editable'=>true)),
  169. array('<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345"> <a href="http://localhost/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;value=1&amp;code=xyz" class="sonata-ba-action sonata-ba-edit-inline"><i class="icon-ban-circle"></i>&nbsp;no</a> </td>', 'boolean', null, array('editable'=>true)),
  170. array('<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>', 'trans', 'action_delete', array('safe'=>false, 'catalogue'=>'SonataAdminBundle')),
  171. array('<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>', 'trans', null, array('safe'=>false, 'catalogue'=>'SonataAdminBundle')),
  172. );
  173. }
  174. /**
  175. * @dataProvider getRenderViewElementTests
  176. */
  177. public function testRenderViewElement($expected, $type, $value, array $options)
  178. {
  179. $object = new \stdClass();
  180. $admin = $this->getMock('Sonata\AdminBundle\Admin\AdminInterface');
  181. $admin->expects($this->any())
  182. ->method('getTemplate')
  183. ->will($this->returnValue('SonataAdminBundle:CRUD:base_show_field.html.twig'));
  184. $admin->expects($this->any())
  185. ->method('id')
  186. ->with($this->equalTo($object))
  187. ->will($this->returnValue(12345));
  188. $admin->expects($this->any())
  189. ->method('trans')
  190. ->will($this->returnCallback(function($id) {
  191. return $id;
  192. }));
  193. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  194. $fieldDescription->expects($this->any())
  195. ->method('getAdmin')
  196. ->will($this->returnValue($admin));
  197. $fieldDescription->expects($this->any())
  198. ->method('getValue')
  199. ->will($this->returnCallback(function() use ($value) {
  200. if ($value instanceof NoValueException) {
  201. throw $value;
  202. }
  203. return $value;
  204. }));
  205. $fieldDescription->expects($this->any())
  206. ->method('getLabel')
  207. ->will($this->returnValue('Data'));
  208. $fieldDescription->expects($this->any())
  209. ->method('getType')
  210. ->will($this->returnValue($type));
  211. $fieldDescription->expects($this->any())
  212. ->method('getOptions')
  213. ->will($this->returnValue($options));
  214. $fieldDescription->expects($this->any())
  215. ->method('getTemplate')
  216. ->will($this->returnCallback(function() use ($type) {
  217. switch ($type) {
  218. case 'boolean':
  219. return 'SonataAdminBundle:CRUD:show_boolean.html.twig';
  220. case 'datetime':
  221. return 'SonataAdminBundle:CRUD:show_datetime.html.twig';
  222. case 'date':
  223. return 'SonataAdminBundle:CRUD:show_date.html.twig';
  224. case 'time':
  225. return 'SonataAdminBundle:CRUD:show_time.html.twig';
  226. case 'currency':
  227. return 'SonataAdminBundle:CRUD:show_currency.html.twig';
  228. case 'percent':
  229. return 'SonataAdminBundle:CRUD:show_percent.html.twig';
  230. case 'array':
  231. return 'SonataAdminBundle:CRUD:show_array.html.twig';
  232. case 'trans':
  233. return 'SonataAdminBundle:CRUD:show_trans.html.twig';
  234. default:
  235. return false;
  236. }
  237. }));
  238. $this->assertEquals($expected, trim(preg_replace('/\s+/', ' ', $this->twigExtension->renderViewElement($fieldDescription, $object))));
  239. }
  240. public function getRenderViewElementTests()
  241. {
  242. return array(
  243. array('<th>Data</th> <td>Example</td>', 'string', 'Example', array('safe' => false)),
  244. array('<th>Data</th> <td>Example</td>', 'text', 'Example', array('safe' => false)),
  245. array('<th>Data</th> <td>Example</td>', 'textarea', 'Example', array('safe' => false)),
  246. array('<th>Data</th> <td>December 24, 2013 10:11</td>', 'datetime', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  247. array('<th>Data</th> <td>24.12.2013 10:11:12</td>', 'datetime', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array('format'=>'d.m.Y H:i:s')),
  248. array('<th>Data</th> <td>December 24, 2013</td>', 'date', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  249. array('<th>Data</th> <td>24.12.2013</td>', 'date', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array('format'=>'d.m.Y')),
  250. array('<th>Data</th> <td>10:11:12</td>', 'time', new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array()),
  251. array('<th>Data</th> <td>10.746135</td>', 'number', 10.746135, array('safe' => false)),
  252. array('<th>Data</th> <td>5678</td>', 'integer', 5678, array('safe' => false)),
  253. array('<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, array()),
  254. array('<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, array('currency' => 'EUR')),
  255. array('<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, array('currency' => 'GBP')),
  256. array('<th>Data</th> <td> [1 => First] [2 => Second] </td>', 'array', array(1 => 'First', 2 => 'Second'), array('safe' => false)),
  257. array('<th>Data</th> <td><i class="icon-ok-circle"></i>yes</td>', 'boolean', true, array()),
  258. array('<th>Data</th> <td><i class="icon-ban-circle"></i>no</td>', 'boolean', false, array()),
  259. array('<th>Data</th> <td> Delete </td>', 'trans', 'action_delete', array('safe'=>false, 'catalogue'=>'SonataAdminBundle')),
  260. //NoValueException
  261. array('<th>Data</th> <td></td>', 'string', new NoValueException(), array('safe' => false)),
  262. array('<th>Data</th> <td></td>', 'text', new NoValueException(), array('safe' => false)),
  263. array('<th>Data</th> <td></td>', 'textarea', new NoValueException(), array('safe' => false)),
  264. array('<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), array()),
  265. array('<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), array('format'=>'d.m.Y H:i:s')),
  266. array('<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), array()),
  267. array('<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), array('format'=>'d.m.Y')),
  268. array('<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), array()),
  269. array('<th>Data</th> <td></td>', 'number', new NoValueException(), array('safe' => false)),
  270. array('<th>Data</th> <td></td>', 'integer', new NoValueException(), array('safe' => false)),
  271. array('<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), array()),
  272. array('<th>Data</th> <td> </td>', 'currency', new NoValueException(), array('currency' => 'EUR')),
  273. array('<th>Data</th> <td> </td>', 'currency', new NoValueException(), array('currency' => 'GBP')),
  274. array('<th>Data</th> <td> </td>', 'array', new NoValueException(), array('safe' => false)),
  275. array('<th>Data</th> <td><i class="icon-ban-circle"></i>no</td>', 'boolean', new NoValueException(), array()),
  276. array('<th>Data</th> <td> </td>', 'trans', new NoValueException(), array('safe'=>false, 'catalogue'=>'SonataAdminBundle')),
  277. );
  278. }
  279. public function testGetValueFromFieldDescription()
  280. {
  281. $object = new \stdClass();
  282. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  283. $fieldDescription->expects($this->any())
  284. ->method('getValue')
  285. ->will($this->returnValue('test123'));
  286. $this->assertEquals('test123', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
  287. }
  288. public function testGetValueFromFieldDescriptionWithNoValueException()
  289. {
  290. $object = new \stdClass();
  291. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  292. $fieldDescription->expects($this->any())
  293. ->method('getValue')
  294. ->will($this->returnCallback(function() {
  295. throw new NoValueException();
  296. }));
  297. $fieldDescription->expects($this->any())
  298. ->method('getAssociationAdmin')
  299. ->will($this->returnValue(null));
  300. $this->assertEquals(null, $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
  301. }
  302. }