SonataAdminExtensionTest.php 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160
  1. <?php
  2. /*
  3. * This file is part of the Sonata Project 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 Psr\Log\LoggerInterface;
  12. use Sonata\AdminBundle\Admin\AdminInterface;
  13. use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
  14. use Sonata\AdminBundle\Admin\Pool;
  15. use Sonata\AdminBundle\Exception\NoValueException;
  16. use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString;
  17. use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
  18. use Symfony\Bridge\Twig\Extension\RoutingExtension;
  19. use Symfony\Bridge\Twig\Extension\TranslationExtension;
  20. use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
  21. use Symfony\Component\Config\FileLocator;
  22. use Symfony\Component\Routing\Generator\UrlGenerator;
  23. use Symfony\Component\Routing\Loader\XmlFileLoader;
  24. use Symfony\Component\Routing\RequestContext;
  25. use Symfony\Component\Translation\Loader\XliffFileLoader;
  26. use Symfony\Component\Translation\MessageSelector;
  27. use Symfony\Component\Translation\Translator;
  28. /**
  29. * Test for SonataAdminExtension.
  30. *
  31. * @author Andrej Hudec <pulzarraider@gmail.com>
  32. */
  33. class SonataAdminExtensionTest extends \PHPUnit_Framework_TestCase
  34. {
  35. /**
  36. * @var SonataAdminExtension
  37. */
  38. private $twigExtension;
  39. /**
  40. * @var \Twig_Environment
  41. */
  42. private $environment;
  43. /**
  44. * @var AdminInterface
  45. */
  46. private $admin;
  47. /**
  48. * @var AdminInterface
  49. */
  50. private $adminBar;
  51. /**
  52. * @var FieldDescriptionInterface
  53. */
  54. private $fieldDescription;
  55. /**
  56. * @var \stdClass
  57. */
  58. private $object;
  59. /**
  60. * @var Pool
  61. */
  62. private $pool;
  63. /**
  64. * @var LoggerInterface
  65. */
  66. private $logger;
  67. /**
  68. * @var string[]
  69. */
  70. private $xEditableTypeMapping;
  71. public function setUp()
  72. {
  73. date_default_timezone_set('Europe/London');
  74. $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
  75. $this->pool = new Pool($container, '', '');
  76. $this->pool->setAdminServiceIds(array('sonata_admin_foo_service'));
  77. $this->pool->setAdminClasses(array('fooClass' => array('sonata_admin_foo_service')));
  78. $this->logger = $this->getMock('Psr\Log\LoggerInterface');
  79. $this->xEditableTypeMapping = array(
  80. 'choice' => 'select',
  81. 'boolean' => 'select',
  82. 'text' => 'text',
  83. 'textarea' => 'textarea',
  84. 'html' => 'textarea',
  85. 'email' => 'email',
  86. 'string' => 'text',
  87. 'smallint' => 'text',
  88. 'bigint' => 'text',
  89. 'integer' => 'number',
  90. 'decimal' => 'number',
  91. 'currency' => 'number',
  92. 'percent' => 'number',
  93. 'url' => 'url',
  94. );
  95. $this->twigExtension = new SonataAdminExtension($this->pool, $this->logger);
  96. $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
  97. $loader = new StubFilesystemLoader(array(
  98. __DIR__.'/../../../Resources/views/CRUD',
  99. ));
  100. $this->environment = new \Twig_Environment($loader, array(
  101. 'strict_variables' => true,
  102. 'cache' => false,
  103. 'autoescape' => 'html',
  104. 'optimizations' => 0,
  105. ));
  106. $this->environment->addExtension($this->twigExtension);
  107. // translation extension
  108. $translator = new Translator('en', new MessageSelector());
  109. $translator->addLoader('xlf', new XliffFileLoader());
  110. $translator->addResource(
  111. 'xlf',
  112. __DIR__.'/../../../Resources/translations/SonataAdminBundle.en.xliff',
  113. 'en',
  114. 'SonataAdminBundle'
  115. );
  116. $this->environment->addExtension(new TranslationExtension($translator));
  117. // routing extension
  118. $xmlFileLoader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../../../Resources/config/routing')));
  119. $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
  120. $xmlFileLoader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../../Fixtures/Resources/config/routing')));
  121. $testRouteCollection = $xmlFileLoader->load('routing.xml');
  122. $routeCollection->addCollection($testRouteCollection);
  123. $requestContext = new RequestContext();
  124. $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
  125. $this->environment->addExtension(new RoutingExtension($urlGenerator));
  126. $this->environment->addExtension(new \Twig_Extensions_Extension_Text());
  127. // initialize object
  128. $this->object = new \stdClass();
  129. // initialize admin
  130. $this->admin = $this->getMock('Sonata\AdminBundle\Admin\AdminInterface');
  131. $this->admin->expects($this->any())
  132. ->method('getCode')
  133. ->will($this->returnValue('xyz'));
  134. $this->admin->expects($this->any())
  135. ->method('id')
  136. ->with($this->equalTo($this->object))
  137. ->will($this->returnValue(12345));
  138. $this->admin->expects($this->any())
  139. ->method('getNormalizedIdentifier')
  140. ->with($this->equalTo($this->object))
  141. ->will($this->returnValue(12345));
  142. $this->admin->expects($this->any())
  143. ->method('trans')
  144. ->will($this->returnCallback(function ($id, $parameters = array(), $domain = null) use ($translator) {
  145. return $translator->trans($id, $parameters, $domain);
  146. }));
  147. $this->adminBar = $this->getMock('Sonata\AdminBundle\Admin\AdminInterface');
  148. $this->adminBar->expects($this->any())
  149. ->method('isGranted')
  150. ->will($this->returnValue(true));
  151. $this->adminBar->expects($this->any())
  152. ->method('getNormalizedIdentifier')
  153. ->with($this->equalTo($this->object))
  154. ->will($this->returnValue(12345));
  155. // for php5.3 BC
  156. $admin = $this->admin;
  157. $adminBar = $this->adminBar;
  158. $container->expects($this->any())
  159. ->method('get')
  160. ->will($this->returnCallback(function ($id) use ($admin, $adminBar) {
  161. if ($id == 'sonata_admin_foo_service') {
  162. return $admin;
  163. } elseif ($id == 'sonata_admin_bar_service') {
  164. return $adminBar;
  165. }
  166. return;
  167. }));
  168. // initialize field description
  169. $this->fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  170. $this->fieldDescription->expects($this->any())
  171. ->method('getName')
  172. ->will($this->returnValue('fd_name'));
  173. $this->fieldDescription->expects($this->any())
  174. ->method('getAdmin')
  175. ->will($this->returnValue($this->admin));
  176. $this->fieldDescription->expects($this->any())
  177. ->method('getLabel')
  178. ->will($this->returnValue('Data'));
  179. }
  180. /**
  181. * @dataProvider getRenderListElementTests
  182. */
  183. public function testRenderListElement($expected, $type, $value, array $options)
  184. {
  185. $this->admin->expects($this->any())
  186. ->method('isGranted')
  187. ->will($this->returnValue(true));
  188. $this->admin->expects($this->any())
  189. ->method('getTemplate')
  190. ->with($this->equalTo('base_list_field'))
  191. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_field.html.twig'));
  192. $this->fieldDescription->expects($this->any())
  193. ->method('getValue')
  194. ->will($this->returnValue($value));
  195. $this->fieldDescription->expects($this->any())
  196. ->method('getType')
  197. ->will($this->returnValue($type));
  198. $this->fieldDescription->expects($this->any())
  199. ->method('getOptions')
  200. ->will($this->returnValue($options));
  201. $this->fieldDescription->expects($this->any())
  202. ->method('getOption')
  203. ->will($this->returnCallback(function ($name, $default = null) use ($options) {
  204. return isset($options[$name]) ? $options[$name] : $default;
  205. }));
  206. $this->fieldDescription->expects($this->any())
  207. ->method('getTemplate')
  208. ->will($this->returnCallback(function () use ($type) {
  209. switch ($type) {
  210. case 'string':
  211. return 'SonataAdminBundle:CRUD:list_string.html.twig';
  212. case 'boolean':
  213. return 'SonataAdminBundle:CRUD:list_boolean.html.twig';
  214. case 'datetime':
  215. return 'SonataAdminBundle:CRUD:list_datetime.html.twig';
  216. case 'date':
  217. return 'SonataAdminBundle:CRUD:list_date.html.twig';
  218. case 'time':
  219. return 'SonataAdminBundle:CRUD:list_time.html.twig';
  220. case 'currency':
  221. return 'SonataAdminBundle:CRUD:list_currency.html.twig';
  222. case 'percent':
  223. return 'SonataAdminBundle:CRUD:list_percent.html.twig';
  224. case 'email':
  225. return 'SonataAdminBundle:CRUD:list_email.html.twig';
  226. case 'choice':
  227. return 'SonataAdminBundle:CRUD:list_choice.html.twig';
  228. case 'array':
  229. return 'SonataAdminBundle:CRUD:list_array.html.twig';
  230. case 'trans':
  231. return 'SonataAdminBundle:CRUD:list_trans.html.twig';
  232. case 'url':
  233. return 'SonataAdminBundle:CRUD:list_url.html.twig';
  234. case 'html':
  235. return 'SonataAdminBundle:CRUD:list_html.html.twig';
  236. case 'nonexistent':
  237. // template doesn`t exist
  238. return 'SonataAdminBundle:CRUD:list_nonexistent_template.html.twig';
  239. default:
  240. return false;
  241. }
  242. }));
  243. $this->assertSame(
  244. $this->removeExtraWhitespace($expected),
  245. $this->removeExtraWhitespace($this->twigExtension->renderListElement(
  246. $this->environment,
  247. $this->object,
  248. $this->fieldDescription
  249. ))
  250. );
  251. }
  252. /**
  253. * @dataProvider getDeprecatedRenderListElementTests
  254. * @group legacy
  255. */
  256. public function testDeprecatedRenderListElement($expected, $value, array $options)
  257. {
  258. $this->admin->expects($this->any())
  259. ->method('isGranted')
  260. ->will($this->returnValue(true));
  261. $this->admin->expects($this->any())
  262. ->method('getTemplate')
  263. ->with($this->equalTo('base_list_field'))
  264. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_field.html.twig'));
  265. $this->fieldDescription->expects($this->any())
  266. ->method('getValue')
  267. ->will($this->returnValue($value));
  268. $this->fieldDescription->expects($this->any())
  269. ->method('getType')
  270. ->will($this->returnValue('nonexistent'));
  271. $this->fieldDescription->expects($this->any())
  272. ->method('getOptions')
  273. ->will($this->returnValue($options));
  274. $this->fieldDescription->expects($this->any())
  275. ->method('getOption')
  276. ->will($this->returnCallback(function ($name, $default = null) use ($options) {
  277. return isset($options[$name]) ? $options[$name] : $default;
  278. }));
  279. $this->fieldDescription->expects($this->any())
  280. ->method('getTemplate')
  281. ->will($this->returnValue('SonataAdminBundle:CRUD:list_nonexistent_template.html.twig'));
  282. $this->assertSame(
  283. $this->removeExtraWhitespace($expected),
  284. $this->removeExtraWhitespace($this->twigExtension->renderListElement(
  285. $this->environment,
  286. $this->object,
  287. $this->fieldDescription
  288. ))
  289. );
  290. }
  291. public function getDeprecatedRenderListElementTests()
  292. {
  293. return array(
  294. array(
  295. '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> Example </td>',
  296. 'Example',
  297. array(),
  298. ),
  299. array(
  300. '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> </td>',
  301. null,
  302. array(),
  303. ),
  304. );
  305. }
  306. public function getRenderListElementTests()
  307. {
  308. return array(
  309. array(
  310. '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
  311. 'string',
  312. 'Example',
  313. array(),
  314. ),
  315. array(
  316. '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
  317. 'string',
  318. null,
  319. array(),
  320. ),
  321. array(
  322. '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
  323. 'text',
  324. 'Example',
  325. array(),
  326. ),
  327. array(
  328. '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
  329. 'text',
  330. null,
  331. array(),
  332. ),
  333. array(
  334. '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
  335. 'textarea',
  336. 'Example',
  337. array(),
  338. ),
  339. array(
  340. '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
  341. 'textarea',
  342. null,
  343. array(),
  344. ),
  345. 'datetime field' => array(
  346. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
  347. December 24, 2013 10:11
  348. </td>',
  349. 'datetime',
  350. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  351. array(),
  352. ),
  353. array(
  354. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
  355. December 24, 2013 18:11
  356. </td>',
  357. 'datetime',
  358. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
  359. array('timezone' => 'Asia/Hong_Kong'),
  360. ),
  361. array(
  362. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
  363. 'datetime',
  364. null,
  365. array(),
  366. ),
  367. array(
  368. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
  369. 24.12.2013 10:11:12
  370. </td>',
  371. 'datetime',
  372. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  373. array('format' => 'd.m.Y H:i:s'),
  374. ),
  375. array(
  376. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
  377. 'datetime',
  378. null,
  379. array('format' => 'd.m.Y H:i:s'),
  380. ),
  381. array(
  382. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
  383. 24.12.2013 18:11:12
  384. </td>',
  385. 'datetime',
  386. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
  387. array('format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'),
  388. ),
  389. array(
  390. '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
  391. 'datetime',
  392. null,
  393. array('format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'),
  394. ),
  395. array(
  396. '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> December 24, 2013 </td>',
  397. 'date',
  398. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  399. array(),
  400. ),
  401. array(
  402. '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
  403. 'date',
  404. null,
  405. array(),
  406. ),
  407. array(
  408. '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> 24.12.2013 </td>',
  409. 'date',
  410. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  411. array('format' => 'd.m.Y'),
  412. ),
  413. array(
  414. '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
  415. 'date',
  416. null,
  417. array('format' => 'd.m.Y'),
  418. ),
  419. array(
  420. '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> 10:11:12 </td>',
  421. 'time',
  422. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  423. array(),
  424. ),
  425. array(
  426. '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
  427. 'time',
  428. null,
  429. array(),
  430. ),
  431. array(
  432. '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
  433. 'number', 10.746135,
  434. array(),
  435. ),
  436. array(
  437. '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
  438. 'number',
  439. null,
  440. array(),
  441. ),
  442. array(
  443. '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
  444. 'integer',
  445. 5678,
  446. array(),
  447. ),
  448. array(
  449. '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
  450. 'integer',
  451. null,
  452. array(),
  453. ),
  454. array(
  455. '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
  456. 'percent',
  457. 10.746135,
  458. array(),
  459. ),
  460. array(
  461. '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
  462. 'percent',
  463. null,
  464. array(),
  465. ),
  466. array(
  467. '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
  468. 'currency',
  469. 10.746135,
  470. array('currency' => 'EUR'),
  471. ),
  472. array(
  473. '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
  474. 'currency',
  475. null,
  476. array('currency' => 'EUR'),
  477. ),
  478. array(
  479. '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
  480. 'currency',
  481. 51.23456,
  482. array('currency' => 'GBP'),
  483. ),
  484. array(
  485. '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
  486. 'currency',
  487. null,
  488. array('currency' => 'GBP'),
  489. ),
  490. array(
  491. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
  492. 'email',
  493. null,
  494. array(),
  495. ),
  496. array(
  497. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:admin@admin.com">admin@admin.com</a> </td>',
  498. 'email',
  499. 'admin@admin.com',
  500. array(),
  501. ),
  502. array(
  503. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
  504. <a href="mailto:admin@admin.com">admin@admin.com</a> </td>',
  505. 'email',
  506. 'admin@admin.com',
  507. array('as_string' => false),
  508. ),
  509. array(
  510. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> admin@admin.com </td>',
  511. 'email',
  512. 'admin@admin.com',
  513. array('as_string' => true),
  514. ),
  515. array(
  516. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
  517. <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('subject' => 'Main Theme', 'body' => 'Message Body')).'">admin@admin.com</a> </td>',
  518. 'email',
  519. 'admin@admin.com',
  520. array('subject' => 'Main Theme', 'body' => 'Message Body'),
  521. ),
  522. array(
  523. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
  524. <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('subject' => 'Main Theme')).'">admin@admin.com</a> </td>',
  525. 'email',
  526. 'admin@admin.com',
  527. array('subject' => 'Main Theme'),
  528. ),
  529. array(
  530. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
  531. <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('body' => 'Message Body')).'">admin@admin.com</a> </td>',
  532. 'email',
  533. 'admin@admin.com',
  534. array('body' => 'Message Body'),
  535. ),
  536. array(
  537. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> admin@admin.com </td>',
  538. 'email',
  539. 'admin@admin.com',
  540. array('as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'),
  541. ),
  542. array(
  543. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> admin@admin.com </td>',
  544. 'email',
  545. 'admin@admin.com',
  546. array('as_string' => true, 'body' => 'Message Body'),
  547. ),
  548. array(
  549. '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> admin@admin.com </td>',
  550. 'email',
  551. 'admin@admin.com',
  552. array('as_string' => true, 'subject' => 'Main Theme'),
  553. ),
  554. array(
  555. '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
  556. [1 => First] [2 => Second]
  557. </td>',
  558. 'array',
  559. array(1 => 'First', 2 => 'Second'),
  560. array(),
  561. ),
  562. array(
  563. '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>',
  564. 'array',
  565. null,
  566. array(),
  567. ),
  568. array(
  569. '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  570. <span class="label label-success">yes</span>
  571. </td>',
  572. 'boolean',
  573. true,
  574. array('editable' => false),
  575. ),
  576. array(
  577. '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  578. <span class="label label-danger">no</span>
  579. </td>',
  580. 'boolean',
  581. false,
  582. array('editable' => false),
  583. ),
  584. array(
  585. '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  586. <span class="label label-danger">no</span>
  587. </td>',
  588. 'boolean',
  589. null,
  590. array('editable' => false),
  591. ),
  592. array(
  593. <<<'EOT'
  594. <td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  595. <span
  596. class="x-editable"
  597. data-type="select"
  598. data-value="1"
  599. data-title="Data"
  600. data-pk="12345"
  601. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  602. data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
  603. >
  604. <span class="label label-success">yes</span>
  605. </span>
  606. </td>
  607. EOT
  608. ,
  609. 'boolean',
  610. true,
  611. array('editable' => true),
  612. ),
  613. array(
  614. <<<'EOT'
  615. <td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  616. <span
  617. class="x-editable"
  618. data-type="select"
  619. data-value=""
  620. data-title="Data"
  621. data-pk="12345"
  622. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  623. data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
  624. >
  625. <span class="label label-danger">no</span> </span>
  626. </td>
  627. EOT
  628. ,
  629. 'boolean',
  630. false,
  631. array('editable' => true),
  632. ),
  633. array(
  634. <<<'EOT'
  635. <td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
  636. <span
  637. class="x-editable"
  638. data-type="select"
  639. data-value=""
  640. data-title="Data"
  641. data-pk="12345"
  642. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  643. data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
  644. <span class="label label-danger">no</span> </span>
  645. </td>
  646. EOT
  647. ,
  648. 'boolean',
  649. null,
  650. array('editable' => true),
  651. ),
  652. array(
  653. '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
  654. 'trans',
  655. 'action_delete',
  656. array('catalogue' => 'SonataAdminBundle'),
  657. ),
  658. array(
  659. '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
  660. 'trans',
  661. null,
  662. array('catalogue' => 'SonataAdminBundle'),
  663. ),
  664. array(
  665. '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
  666. 'trans',
  667. 'action_delete',
  668. array('format' => '%s', 'catalogue' => 'SonataAdminBundle'),
  669. ),
  670. array(
  671. '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
  672. action.action_delete
  673. </td>',
  674. 'trans',
  675. 'action_delete',
  676. array('format' => 'action.%s'),
  677. ),
  678. array(
  679. '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
  680. action.action_delete
  681. </td>',
  682. 'trans',
  683. 'action_delete',
  684. array('format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'),
  685. ),
  686. array(
  687. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
  688. 'choice',
  689. 'Status1',
  690. array(),
  691. ),
  692. array(
  693. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
  694. 'choice',
  695. array('Status1'),
  696. array('choices' => array(), 'multiple' => true),
  697. ),
  698. array(
  699. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
  700. 'choice',
  701. 'Status1',
  702. array('choices' => array('Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3')),
  703. ),
  704. array(
  705. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
  706. 'choice',
  707. null,
  708. array('choices' => array('Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3')),
  709. ),
  710. array(
  711. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  712. NoValidKeyInChoices
  713. </td>',
  714. 'choice',
  715. 'NoValidKeyInChoices',
  716. array('choices' => array('Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3')),
  717. ),
  718. array(
  719. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
  720. 'choice',
  721. 'Foo',
  722. array('catalogue' => 'SonataAdminBundle', 'choices' => array(
  723. 'Foo' => 'action_delete',
  724. 'Status2' => 'Alias2',
  725. 'Status3' => 'Alias3',
  726. )),
  727. ),
  728. array(
  729. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
  730. 'choice',
  731. array('Status1', 'Status3'),
  732. array('choices' => array(
  733. 'Status1' => 'Alias1',
  734. 'Status2' => 'Alias2',
  735. 'Status3' => 'Alias3',
  736. ), 'multiple' => true), ),
  737. array(
  738. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
  739. 'choice',
  740. array('Status1', 'Status3'),
  741. array('choices' => array(
  742. 'Status1' => 'Alias1',
  743. 'Status2' => 'Alias2',
  744. 'Status3' => 'Alias3',
  745. ), 'multiple' => true, 'delimiter' => ' | '), ),
  746. array(
  747. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
  748. 'choice',
  749. null,
  750. array('choices' => array(
  751. 'Status1' => 'Alias1',
  752. 'Status2' => 'Alias2',
  753. 'Status3' => 'Alias3',
  754. ), 'multiple' => true),
  755. ),
  756. array(
  757. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  758. NoValidKeyInChoices
  759. </td>',
  760. 'choice',
  761. array('NoValidKeyInChoices'),
  762. array('choices' => array(
  763. 'Status1' => 'Alias1',
  764. 'Status2' => 'Alias2',
  765. 'Status3' => 'Alias3',
  766. ), 'multiple' => true),
  767. ),
  768. array(
  769. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  770. NoValidKeyInChoices, Alias2
  771. </td>',
  772. 'choice',
  773. array('NoValidKeyInChoices', 'Status2'),
  774. array('choices' => array(
  775. 'Status1' => 'Alias1',
  776. 'Status2' => 'Alias2',
  777. 'Status3' => 'Alias3',
  778. ), 'multiple' => true),
  779. ),
  780. array(
  781. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
  782. 'choice',
  783. array('Foo', 'Status3'),
  784. array('catalogue' => 'SonataAdminBundle', 'choices' => array(
  785. 'Foo' => 'action_delete',
  786. 'Status2' => 'Alias2',
  787. 'Status3' => 'Alias3',
  788. ), 'multiple' => true),
  789. ),
  790. array(
  791. '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  792. &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
  793. </td>',
  794. 'choice',
  795. array('Status1', 'Status3'),
  796. array('choices' => array(
  797. 'Status1' => '<b>Alias1</b>',
  798. 'Status2' => '<b>Alias2</b>',
  799. 'Status3' => '<b>Alias3</b>',
  800. ), 'multiple' => true), ),
  801. array(
  802. <<<'EOT'
  803. <td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  804. <span
  805. class="x-editable"
  806. data-type="select"
  807. data-value="Status1"
  808. data-title="Data"
  809. data-pk="12345"
  810. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  811. data-source="[]"
  812. >
  813. Status1
  814. </span>
  815. </td>
  816. EOT
  817. ,
  818. 'choice',
  819. 'Status1',
  820. array('editable' => true),
  821. ),
  822. array(
  823. <<<'EOT'
  824. <td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  825. <span
  826. class="x-editable"
  827. data-type="select"
  828. data-value="Status1"
  829. data-title="Data"
  830. data-pk="12345"
  831. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  832. data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
  833. Alias1 </span>
  834. </td>
  835. EOT
  836. ,
  837. 'choice',
  838. 'Status1',
  839. array(
  840. 'editable' => true,
  841. 'choices' => array(
  842. 'Status1' => 'Alias1',
  843. 'Status2' => 'Alias2',
  844. 'Status3' => 'Alias3',
  845. ),
  846. ),
  847. ),
  848. array(
  849. <<<'EOT'
  850. <td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  851. <span
  852. class="x-editable"
  853. data-type="select"
  854. data-value=""
  855. data-title="Data"
  856. data-pk="12345"
  857. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  858. data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
  859. </span>
  860. </td>
  861. EOT
  862. ,
  863. 'choice',
  864. null,
  865. array(
  866. 'editable' => true,
  867. 'choices' => array(
  868. 'Status1' => 'Alias1',
  869. 'Status2' => 'Alias2',
  870. 'Status3' => 'Alias3',
  871. ),
  872. ),
  873. ),
  874. array(
  875. <<<'EOT'
  876. <td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  877. <span
  878. class="x-editable"
  879. data-type="select"
  880. data-value="NoValidKeyInChoices"
  881. data-title="Data" data-pk="12345"
  882. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  883. data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
  884. NoValidKeyInChoices
  885. </span>
  886. </td>
  887. EOT
  888. ,
  889. 'choice',
  890. 'NoValidKeyInChoices',
  891. array(
  892. 'editable' => true,
  893. 'choices' => array(
  894. 'Status1' => 'Alias1',
  895. 'Status2' => 'Alias2',
  896. 'Status3' => 'Alias3',
  897. ),
  898. ),
  899. ),
  900. array(
  901. <<<'EOT'
  902. <td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
  903. <span
  904. class="x-editable"
  905. data-type="select"
  906. data-value="Foo"
  907. data-title="Data"
  908. data-pk="12345"
  909. data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=xyz"
  910. data-source="[{&quot;value&quot;:&quot;Foo&quot;,&quot;text&quot;:&quot;Delete&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
  911. Delete
  912. </span>
  913. </td>
  914. EOT
  915. ,
  916. 'choice',
  917. 'Foo',
  918. array(
  919. 'editable' => true,
  920. 'catalogue' => 'SonataAdminBundle',
  921. 'choices' => array(
  922. 'Foo' => 'action_delete',
  923. 'Status2' => 'Alias2',
  924. 'Status3' => 'Alias3',
  925. ),
  926. ),
  927. ),
  928. array(
  929. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
  930. 'url',
  931. null,
  932. array(),
  933. ),
  934. array(
  935. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
  936. 'url',
  937. null,
  938. array('url' => 'http://example.com'),
  939. ),
  940. array(
  941. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
  942. 'url',
  943. null,
  944. array('route' => array('name' => 'sonata_admin_foo')),
  945. ),
  946. array(
  947. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  948. <a href="http://example.com">http://example.com</a>
  949. </td>',
  950. 'url',
  951. 'http://example.com',
  952. array(),
  953. ),
  954. array(
  955. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  956. <a href="https://example.com">https://example.com</a>
  957. </td>',
  958. 'url',
  959. 'https://example.com',
  960. array(),
  961. ),
  962. array(
  963. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  964. <a href="http://example.com">example.com</a>
  965. </td>',
  966. 'url',
  967. 'http://example.com',
  968. array('hide_protocol' => true),
  969. ),
  970. array(
  971. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  972. <a href="https://example.com">example.com</a>
  973. </td>',
  974. 'url',
  975. 'https://example.com',
  976. array('hide_protocol' => true),
  977. ),
  978. array(
  979. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  980. <a href="http://example.com">http://example.com</a>
  981. </td>',
  982. 'url',
  983. 'http://example.com',
  984. array('hide_protocol' => false),
  985. ),
  986. array(
  987. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  988. <a href="https://example.com">https://example.com</a>
  989. </td>',
  990. 'url',
  991. 'https://example.com',
  992. array('hide_protocol' => false),
  993. ),
  994. array(
  995. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  996. <a href="http://example.com">Foo</a>
  997. </td>',
  998. 'url',
  999. 'Foo',
  1000. array('url' => 'http://example.com'),
  1001. ),
  1002. array(
  1003. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1004. <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
  1005. </td>',
  1006. 'url',
  1007. '<b>Foo</b>',
  1008. array('url' => 'http://example.com'),
  1009. ),
  1010. array(
  1011. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1012. <a href="/foo">Foo</a>
  1013. </td>',
  1014. 'url',
  1015. 'Foo',
  1016. array('route' => array('name' => 'sonata_admin_foo')),
  1017. ),
  1018. array(
  1019. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1020. <a href="http://localhost/foo">Foo</a>
  1021. </td>',
  1022. 'url',
  1023. 'Foo',
  1024. array('route' => array('name' => 'sonata_admin_foo', 'absolute' => true)),
  1025. ),
  1026. array(
  1027. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1028. <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
  1029. </td>',
  1030. 'url',
  1031. 'http://foo/bar?a=b&c=123456789',
  1032. array('route' => array('name' => 'sonata_admin_foo'),
  1033. 'hide_protocol' => true, ),
  1034. ),
  1035. array(
  1036. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1037. <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
  1038. </td>',
  1039. 'url',
  1040. 'http://foo/bar?a=b&c=123456789',
  1041. array(
  1042. 'route' => array('name' => 'sonata_admin_foo', 'absolute' => true),
  1043. 'hide_protocol' => true,
  1044. ),
  1045. ),
  1046. array(
  1047. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1048. <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
  1049. </td>',
  1050. 'url',
  1051. 'Foo',
  1052. array(
  1053. 'route' => array('name' => 'sonata_admin_foo_param',
  1054. 'parameters' => array('param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'), ),
  1055. ),
  1056. ),
  1057. array(
  1058. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1059. <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
  1060. </td>',
  1061. 'url',
  1062. 'Foo',
  1063. array(
  1064. 'route' => array('name' => 'sonata_admin_foo_param',
  1065. 'absolute' => true,
  1066. 'parameters' => array('param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'), ),
  1067. ),
  1068. ),
  1069. array(
  1070. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1071. <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
  1072. </td>',
  1073. 'url',
  1074. 'Foo',
  1075. array(
  1076. 'route' => array('name' => 'sonata_admin_foo_object',
  1077. 'parameters' => array('param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'),
  1078. 'identifier_parameter_name' => 'barId', ),
  1079. ),
  1080. ),
  1081. array(
  1082. '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
  1083. <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
  1084. </td>',
  1085. 'url',
  1086. 'Foo',
  1087. array(
  1088. 'route' => array('name' => 'sonata_admin_foo_object',
  1089. 'absolute' => true,
  1090. 'parameters' => array('param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'),
  1091. 'identifier_parameter_name' => 'barId', ),
  1092. ),
  1093. ),
  1094. array(
  1095. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1096. <p><strong>Creating a Template for the Field</strong> and form</p>
  1097. </td>',
  1098. 'html',
  1099. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1100. array(),
  1101. ),
  1102. array(
  1103. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1104. Creating a Template for the Field and form
  1105. </td>',
  1106. 'html',
  1107. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1108. array('strip' => true),
  1109. ),
  1110. array(
  1111. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1112. Creating a Template for the Fi...
  1113. </td>',
  1114. 'html',
  1115. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1116. array('truncate' => true),
  1117. ),
  1118. array(
  1119. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creating a... </td>',
  1120. 'html',
  1121. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1122. array('truncate' => array('length' => 10)),
  1123. ),
  1124. array(
  1125. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1126. Creating a Template for the Field...
  1127. </td>',
  1128. 'html',
  1129. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1130. array('truncate' => array('preserve' => true)),
  1131. ),
  1132. array(
  1133. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1134. Creating a Template for the Fi etc.
  1135. </td>',
  1136. 'html',
  1137. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1138. array('truncate' => array('separator' => ' etc.')),
  1139. ),
  1140. array(
  1141. '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
  1142. Creating a Template for[...]
  1143. </td>',
  1144. 'html',
  1145. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1146. array(
  1147. 'truncate' => array(
  1148. 'length' => 20,
  1149. 'preserve' => true,
  1150. 'separator' => '[...]',
  1151. ),
  1152. ),
  1153. ),
  1154. );
  1155. }
  1156. /**
  1157. * @group legacy
  1158. */
  1159. public function testRenderListElementNonExistentTemplate()
  1160. {
  1161. $this->admin->expects($this->once())
  1162. ->method('getTemplate')
  1163. ->with($this->equalTo('base_list_field'))
  1164. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_field.html.twig'));
  1165. $this->fieldDescription->expects($this->once())
  1166. ->method('getValue')
  1167. ->will($this->returnValue('Foo'));
  1168. $this->fieldDescription->expects($this->once())
  1169. ->method('getFieldName')
  1170. ->will($this->returnValue('Foo_name'));
  1171. $this->fieldDescription->expects($this->exactly(2))
  1172. ->method('getType')
  1173. ->will($this->returnValue('nonexistent'));
  1174. $this->fieldDescription->expects($this->once())
  1175. ->method('getTemplate')
  1176. ->will($this->returnValue('SonataAdminBundle:CRUD:list_nonexistent_template.html.twig'));
  1177. $this->logger->expects($this->once())
  1178. ->method('warning')
  1179. ->with(($this->stringStartsWith($this->removeExtraWhitespace(
  1180. 'An error occured trying to load the template
  1181. "SonataAdminBundle:CRUD:list_nonexistent_template.html.twig"
  1182. for the field "Foo_name", the default template
  1183. "SonataAdminBundle:CRUD:base_list_field.html.twig" was used
  1184. instead.'
  1185. ))));
  1186. $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
  1187. }
  1188. /**
  1189. * @expectedException Twig_Error_Loader
  1190. * @expectedExceptionMessage Unable to find template "base_list_nonexistent_field.html.twig"
  1191. * @group legacy
  1192. */
  1193. public function testRenderListElementErrorLoadingTemplate()
  1194. {
  1195. $this->admin->expects($this->once())
  1196. ->method('getTemplate')
  1197. ->with($this->equalTo('base_list_field'))
  1198. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_nonexistent_field.html.twig'));
  1199. $this->fieldDescription->expects($this->once())
  1200. ->method('getTemplate')
  1201. ->will($this->returnValue('SonataAdminBundle:CRUD:list_nonexistent_template.html.twig'));
  1202. $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
  1203. }
  1204. /**
  1205. * @dataProvider getRenderViewElementTests
  1206. */
  1207. public function testRenderViewElement($expected, $type, $value, array $options)
  1208. {
  1209. $this->admin->expects($this->any())
  1210. ->method('getTemplate')
  1211. ->will($this->returnValue('SonataAdminBundle:CRUD:base_show_field.html.twig'));
  1212. $this->fieldDescription->expects($this->any())
  1213. ->method('getValue')
  1214. ->will($this->returnCallback(function () use ($value) {
  1215. if ($value instanceof NoValueException) {
  1216. throw $value;
  1217. }
  1218. return $value;
  1219. }));
  1220. $this->fieldDescription->expects($this->any())
  1221. ->method('getType')
  1222. ->will($this->returnValue($type));
  1223. $this->fieldDescription->expects($this->any())
  1224. ->method('getOptions')
  1225. ->will($this->returnValue($options));
  1226. $this->fieldDescription->expects($this->any())
  1227. ->method('getTemplate')
  1228. ->will($this->returnCallback(function () use ($type) {
  1229. switch ($type) {
  1230. case 'boolean':
  1231. return 'SonataAdminBundle:CRUD:show_boolean.html.twig';
  1232. case 'datetime':
  1233. return 'SonataAdminBundle:CRUD:show_datetime.html.twig';
  1234. case 'date':
  1235. return 'SonataAdminBundle:CRUD:show_date.html.twig';
  1236. case 'time':
  1237. return 'SonataAdminBundle:CRUD:show_time.html.twig';
  1238. case 'currency':
  1239. return 'SonataAdminBundle:CRUD:show_currency.html.twig';
  1240. case 'percent':
  1241. return 'SonataAdminBundle:CRUD:show_percent.html.twig';
  1242. case 'email':
  1243. return 'SonataAdminBundle:CRUD:show_email.html.twig';
  1244. case 'choice':
  1245. return 'SonataAdminBundle:CRUD:show_choice.html.twig';
  1246. case 'array':
  1247. return 'SonataAdminBundle:CRUD:show_array.html.twig';
  1248. case 'trans':
  1249. return 'SonataAdminBundle:CRUD:show_trans.html.twig';
  1250. case 'url':
  1251. return 'SonataAdminBundle:CRUD:show_url.html.twig';
  1252. case 'html':
  1253. return 'SonataAdminBundle:CRUD:show_html.html.twig';
  1254. default:
  1255. return false;
  1256. }
  1257. }));
  1258. $this->assertSame($expected, trim(preg_replace(
  1259. '/\s+/',
  1260. ' ',
  1261. $this->twigExtension->renderViewElement(
  1262. $this->environment,
  1263. $this->fieldDescription,
  1264. $this->object
  1265. )
  1266. )));
  1267. }
  1268. public function getRenderViewElementTests()
  1269. {
  1270. return array(
  1271. array('<th>Data</th> <td>Example</td>', 'string', 'Example', array('safe' => false)),
  1272. array('<th>Data</th> <td>Example</td>', 'text', 'Example', array('safe' => false)),
  1273. array('<th>Data</th> <td>Example</td>', 'textarea', 'Example', array('safe' => false)),
  1274. array(
  1275. '<th>Data</th> <td>December 24, 2013 10:11</td>',
  1276. 'datetime',
  1277. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), array(),
  1278. ),
  1279. array(
  1280. '<th>Data</th> <td>24.12.2013 10:11:12</td>',
  1281. 'datetime',
  1282. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  1283. array('format' => 'd.m.Y H:i:s'),
  1284. ),
  1285. array(
  1286. '<th>Data</th> <td>December 24, 2013</td>',
  1287. 'date',
  1288. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  1289. array(),
  1290. ),
  1291. array(
  1292. '<th>Data</th> <td>24.12.2013</td>',
  1293. 'date',
  1294. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  1295. array('format' => 'd.m.Y'),
  1296. ),
  1297. array(
  1298. '<th>Data</th> <td>10:11:12</td>',
  1299. 'time',
  1300. new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
  1301. array(),
  1302. ),
  1303. array('<th>Data</th> <td>10.746135</td>', 'number', 10.746135, array('safe' => false)),
  1304. array('<th>Data</th> <td>5678</td>', 'integer', 5678, array('safe' => false)),
  1305. array('<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, array()),
  1306. array('<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, array('currency' => 'EUR')),
  1307. array('<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, array('currency' => 'GBP')),
  1308. array(
  1309. '<th>Data</th> <td> [1 => First] <br> [2 => Second] </td>',
  1310. 'array',
  1311. array(1 => 'First', 2 => 'Second'),
  1312. array('safe' => false),
  1313. ),
  1314. array(
  1315. '<th>Data</th> <td> [1 => First] [2 => Second] </td>',
  1316. 'array',
  1317. array(1 => 'First', 2 => 'Second'),
  1318. array('safe' => false, 'inline' => true),
  1319. ),
  1320. array(
  1321. '<th>Data</th> <td><span class="label label-success">yes</span></td>',
  1322. 'boolean',
  1323. true,
  1324. array(),
  1325. ),
  1326. array('<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, array()),
  1327. array(
  1328. '<th>Data</th> <td> Delete </td>',
  1329. 'trans',
  1330. 'action_delete',
  1331. array('safe' => false, 'catalogue' => 'SonataAdminBundle'),
  1332. ),
  1333. array('<th>Data</th> <td>Status1</td>', 'choice', 'Status1', array('safe' => false)),
  1334. array(
  1335. '<th>Data</th> <td>Alias1</td>',
  1336. 'choice',
  1337. 'Status1',
  1338. array('safe' => false, 'choices' => array(
  1339. 'Status1' => 'Alias1',
  1340. 'Status2' => 'Alias2',
  1341. 'Status3' => 'Alias3',
  1342. )),
  1343. ),
  1344. array(
  1345. '<th>Data</th> <td>NoValidKeyInChoices</td>',
  1346. 'choice',
  1347. 'NoValidKeyInChoices',
  1348. array('safe' => false, 'choices' => array(
  1349. 'Status1' => 'Alias1',
  1350. 'Status2' => 'Alias2',
  1351. 'Status3' => 'Alias3',
  1352. )),
  1353. ),
  1354. array(
  1355. '<th>Data</th> <td>Delete</td>',
  1356. 'choice',
  1357. 'Foo',
  1358. array('safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => array(
  1359. 'Foo' => 'action_delete',
  1360. 'Status2' => 'Alias2',
  1361. 'Status3' => 'Alias3',
  1362. )),
  1363. ),
  1364. array(
  1365. '<th>Data</th> <td>NoValidKeyInChoices</td>',
  1366. 'choice',
  1367. array('NoValidKeyInChoices'),
  1368. array('safe' => false, 'choices' => array(
  1369. 'Status1' => 'Alias1',
  1370. 'Status2' => 'Alias2',
  1371. 'Status3' => 'Alias3',
  1372. ), 'multiple' => true),
  1373. ),
  1374. array(
  1375. '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
  1376. 'choice',
  1377. array('NoValidKeyInChoices', 'Status2'),
  1378. array('safe' => false, 'choices' => array(
  1379. 'Status1' => 'Alias1',
  1380. 'Status2' => 'Alias2',
  1381. 'Status3' => 'Alias3',
  1382. ), 'multiple' => true),
  1383. ),
  1384. array(
  1385. '<th>Data</th> <td>Alias1, Alias3</td>',
  1386. 'choice',
  1387. array('Status1', 'Status3'),
  1388. array('safe' => false, 'choices' => array(
  1389. 'Status1' => 'Alias1',
  1390. 'Status2' => 'Alias2',
  1391. 'Status3' => 'Alias3',
  1392. ), 'multiple' => true),
  1393. ),
  1394. array(
  1395. '<th>Data</th> <td>Alias1 | Alias3</td>',
  1396. 'choice',
  1397. array('Status1', 'Status3'), array('safe' => false, 'choices' => array(
  1398. 'Status1' => 'Alias1',
  1399. 'Status2' => 'Alias2',
  1400. 'Status3' => 'Alias3',
  1401. ), 'multiple' => true, 'delimiter' => ' | '),
  1402. ),
  1403. array(
  1404. '<th>Data</th> <td>Delete, Alias3</td>',
  1405. 'choice',
  1406. array('Foo', 'Status3'),
  1407. array('safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => array(
  1408. 'Foo' => 'action_delete',
  1409. 'Status2' => 'Alias2',
  1410. 'Status3' => 'Alias3',
  1411. ), 'multiple' => true),
  1412. ),
  1413. array(
  1414. '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
  1415. 'choice',
  1416. array('Status1', 'Status3'),
  1417. array('safe' => true, 'choices' => array(
  1418. 'Status1' => '<b>Alias1</b>',
  1419. 'Status2' => '<b>Alias2</b>',
  1420. 'Status3' => '<b>Alias3</b>',
  1421. ), 'multiple' => true),
  1422. ),
  1423. array(
  1424. '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
  1425. 'choice',
  1426. array('Status1', 'Status3'),
  1427. array('safe' => false, 'choices' => array(
  1428. 'Status1' => '<b>Alias1</b>',
  1429. 'Status2' => '<b>Alias2</b>',
  1430. 'Status3' => '<b>Alias3</b>',
  1431. ), 'multiple' => true),
  1432. ),
  1433. array(
  1434. '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
  1435. 'url',
  1436. 'http://example.com',
  1437. array('safe' => false),
  1438. ),
  1439. array(
  1440. '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
  1441. 'url',
  1442. 'https://example.com',
  1443. array('safe' => false),
  1444. ),
  1445. array(
  1446. '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
  1447. 'url',
  1448. 'http://example.com',
  1449. array('safe' => false, 'hide_protocol' => true),
  1450. ),
  1451. array(
  1452. '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
  1453. 'url',
  1454. 'https://example.com',
  1455. array('safe' => false, 'hide_protocol' => true),
  1456. ),
  1457. array(
  1458. '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
  1459. 'url',
  1460. 'http://example.com',
  1461. array('safe' => false, 'hide_protocol' => false),
  1462. ),
  1463. array(
  1464. '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
  1465. 'url',
  1466. 'https://example.com',
  1467. array('safe' => false,
  1468. 'hide_protocol' => false, ),
  1469. ),
  1470. array(
  1471. '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
  1472. 'url',
  1473. 'Foo',
  1474. array('safe' => false, 'url' => 'http://example.com'),
  1475. ),
  1476. array(
  1477. '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
  1478. 'url',
  1479. '<b>Foo</b>',
  1480. array('safe' => false, 'url' => 'http://example.com'),
  1481. ),
  1482. array(
  1483. '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
  1484. 'url',
  1485. '<b>Foo</b>',
  1486. array('safe' => true, 'url' => 'http://example.com'),
  1487. ),
  1488. array(
  1489. '<th>Data</th> <td><a href="/foo">Foo</a></td>',
  1490. 'url',
  1491. 'Foo',
  1492. array('safe' => false, 'route' => array('name' => 'sonata_admin_foo')),
  1493. ),
  1494. array(
  1495. '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
  1496. 'url',
  1497. 'Foo',
  1498. array('safe' => false, 'route' => array(
  1499. 'name' => 'sonata_admin_foo',
  1500. 'absolute' => true,
  1501. )),
  1502. ),
  1503. array(
  1504. '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
  1505. 'url',
  1506. 'http://foo/bar?a=b&c=123456789',
  1507. array(
  1508. 'safe' => false,
  1509. 'route' => array('name' => 'sonata_admin_foo'),
  1510. 'hide_protocol' => true,
  1511. ),
  1512. ),
  1513. array(
  1514. '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
  1515. 'url',
  1516. 'http://foo/bar?a=b&c=123456789',
  1517. array('safe' => false, 'route' => array(
  1518. 'name' => 'sonata_admin_foo',
  1519. 'absolute' => true,
  1520. ), 'hide_protocol' => true),
  1521. ),
  1522. array(
  1523. '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
  1524. 'url',
  1525. 'Foo',
  1526. array('safe' => false, 'route' => array(
  1527. 'name' => 'sonata_admin_foo_param',
  1528. 'parameters' => array('param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'),
  1529. )),
  1530. ),
  1531. array(
  1532. '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
  1533. 'url',
  1534. 'Foo',
  1535. array('safe' => false, 'route' => array(
  1536. 'name' => 'sonata_admin_foo_param',
  1537. 'absolute' => true,
  1538. 'parameters' => array(
  1539. 'param1' => 'abcd',
  1540. 'param2' => 'efgh',
  1541. 'param3' => 'ijkl',
  1542. ),
  1543. )),
  1544. ),
  1545. array(
  1546. '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
  1547. 'url',
  1548. 'Foo',
  1549. array('safe' => false, 'route' => array(
  1550. 'name' => 'sonata_admin_foo_object',
  1551. 'parameters' => array(
  1552. 'param1' => 'abcd',
  1553. 'param2' => 'efgh',
  1554. 'param3' => 'ijkl',
  1555. ),
  1556. 'identifier_parameter_name' => 'barId',
  1557. )),
  1558. ),
  1559. array(
  1560. '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
  1561. 'url',
  1562. 'Foo',
  1563. array('safe' => false, 'route' => array(
  1564. 'name' => 'sonata_admin_foo_object',
  1565. 'absolute' => true,
  1566. 'parameters' => array(
  1567. 'param1' => 'abcd',
  1568. 'param2' => 'efgh',
  1569. 'param3' => 'ijkl',
  1570. ),
  1571. 'identifier_parameter_name' => 'barId',
  1572. )),
  1573. ),
  1574. array(
  1575. '<th>Data</th> <td> &nbsp;</td>',
  1576. 'email',
  1577. null,
  1578. array(),
  1579. ),
  1580. array(
  1581. '<th>Data</th> <td> <a href="mailto:admin@admin.com">admin@admin.com</a></td>',
  1582. 'email',
  1583. 'admin@admin.com',
  1584. array(),
  1585. ),
  1586. array(
  1587. '<th>Data</th> <td> <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('subject' => 'Main Theme', 'body' => 'Message Body')).'">admin@admin.com</a></td>',
  1588. 'email',
  1589. 'admin@admin.com',
  1590. array('subject' => 'Main Theme', 'body' => 'Message Body'),
  1591. ),
  1592. array(
  1593. '<th>Data</th> <td> <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('subject' => 'Main Theme')).'">admin@admin.com</a></td>',
  1594. 'email',
  1595. 'admin@admin.com',
  1596. array('subject' => 'Main Theme'),
  1597. ),
  1598. array(
  1599. '<th>Data</th> <td> <a href="mailto:admin@admin.com?'.$this->buildTwigLikeUrl(array('body' => 'Message Body')).'">admin@admin.com</a></td>',
  1600. 'email',
  1601. 'admin@admin.com',
  1602. array('body' => 'Message Body'),
  1603. ),
  1604. array(
  1605. '<th>Data</th> <td> admin@admin.com</td>',
  1606. 'email',
  1607. 'admin@admin.com',
  1608. array('as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'),
  1609. ),
  1610. array(
  1611. '<th>Data</th> <td> admin@admin.com</td>',
  1612. 'email',
  1613. 'admin@admin.com',
  1614. array('as_string' => true, 'subject' => 'Main Theme'),
  1615. ),
  1616. array(
  1617. '<th>Data</th> <td> admin@admin.com</td>',
  1618. 'email',
  1619. 'admin@admin.com',
  1620. array('as_string' => true, 'body' => 'Message Body'),
  1621. ),
  1622. array(
  1623. '<th>Data</th> <td> <a href="mailto:admin@admin.com">admin@admin.com</a></td>',
  1624. 'email',
  1625. 'admin@admin.com',
  1626. array('as_string' => false),
  1627. ),
  1628. array(
  1629. '<th>Data</th> <td> admin@admin.com</td>',
  1630. 'email',
  1631. 'admin@admin.com',
  1632. array('as_string' => true),
  1633. ),
  1634. array(
  1635. '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
  1636. 'html',
  1637. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1638. array(),
  1639. ),
  1640. array(
  1641. '<th>Data</th> <td>Creating a Template for the Field and form </td>',
  1642. 'html',
  1643. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1644. array('strip' => true),
  1645. ),
  1646. array(
  1647. '<th>Data</th> <td> Creating a Template for the Fi... </td>',
  1648. 'html',
  1649. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1650. array('truncate' => true),
  1651. ),
  1652. array(
  1653. '<th>Data</th> <td> Creating a... </td>',
  1654. 'html',
  1655. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1656. array('truncate' => array('length' => 10)),
  1657. ),
  1658. array(
  1659. '<th>Data</th> <td> Creating a Template for the Field... </td>',
  1660. 'html',
  1661. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1662. array('truncate' => array('preserve' => true)),
  1663. ),
  1664. array(
  1665. '<th>Data</th> <td> Creating a Template for the Fi etc. </td>',
  1666. 'html',
  1667. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1668. array('truncate' => array('separator' => ' etc.')),
  1669. ),
  1670. array(
  1671. '<th>Data</th> <td> Creating a Template for[...] </td>',
  1672. 'html',
  1673. '<p><strong>Creating a Template for the Field</strong> and form</p>',
  1674. array(
  1675. 'truncate' => array(
  1676. 'length' => 20,
  1677. 'preserve' => true,
  1678. 'separator' => '[...]',
  1679. ),
  1680. ),
  1681. ),
  1682. // NoValueException
  1683. array('<th>Data</th> <td></td>', 'string', new NoValueException(), array('safe' => false)),
  1684. array('<th>Data</th> <td></td>', 'text', new NoValueException(), array('safe' => false)),
  1685. array('<th>Data</th> <td></td>', 'textarea', new NoValueException(), array('safe' => false)),
  1686. array('<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), array()),
  1687. array(
  1688. '<th>Data</th> <td>&nbsp;</td>',
  1689. 'datetime',
  1690. new NoValueException(),
  1691. array('format' => 'd.m.Y H:i:s'),
  1692. ),
  1693. array('<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), array()),
  1694. array('<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), array('format' => 'd.m.Y')),
  1695. array('<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), array()),
  1696. array('<th>Data</th> <td></td>', 'number', new NoValueException(), array('safe' => false)),
  1697. array('<th>Data</th> <td></td>', 'integer', new NoValueException(), array('safe' => false)),
  1698. array('<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), array()),
  1699. array('<th>Data</th> <td> </td>', 'currency', new NoValueException(), array('currency' => 'EUR')),
  1700. array('<th>Data</th> <td> </td>', 'currency', new NoValueException(), array('currency' => 'GBP')),
  1701. array('<th>Data</th> <td> </td>', 'array', new NoValueException(), array('safe' => false)),
  1702. array(
  1703. '<th>Data</th> <td><span class="label label-danger">no</span></td>',
  1704. 'boolean',
  1705. new NoValueException(),
  1706. array(),
  1707. ),
  1708. array(
  1709. '<th>Data</th> <td> </td>',
  1710. 'trans',
  1711. new NoValueException(),
  1712. array('safe' => false, 'catalogue' => 'SonataAdminBundle'),
  1713. ),
  1714. array(
  1715. '<th>Data</th> <td></td>',
  1716. 'choice',
  1717. new NoValueException(),
  1718. array('safe' => false, 'choices' => array()),
  1719. ),
  1720. array(
  1721. '<th>Data</th> <td></td>',
  1722. 'choice',
  1723. new NoValueException(),
  1724. array('safe' => false, 'choices' => array(), 'multiple' => true),
  1725. ),
  1726. array('<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), array()),
  1727. array(
  1728. '<th>Data</th> <td>&nbsp;</td>',
  1729. 'url',
  1730. new NoValueException(),
  1731. array('url' => 'http://example.com'),
  1732. ),
  1733. array(
  1734. '<th>Data</th> <td>&nbsp;</td>',
  1735. 'url',
  1736. new NoValueException(),
  1737. array('route' => array('name' => 'sonata_admin_foo')),
  1738. ),
  1739. );
  1740. }
  1741. public function testGetValueFromFieldDescription()
  1742. {
  1743. $object = new \stdClass();
  1744. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  1745. $fieldDescription->expects($this->any())
  1746. ->method('getValue')
  1747. ->will($this->returnValue('test123'));
  1748. $this->assertSame('test123', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
  1749. }
  1750. public function testGetValueFromFieldDescriptionWithRemoveLoopException()
  1751. {
  1752. $object = $this->getMock('\ArrayAccess');
  1753. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  1754. try {
  1755. $this->assertSame(
  1756. 'anything',
  1757. $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription, array('loop' => true))
  1758. );
  1759. } catch (\RuntimeException $e) {
  1760. $this->assertContains('remove the loop requirement', $e->getMessage());
  1761. return;
  1762. }
  1763. $this->fail('Failed asserting that exception of type "\RuntimeException" is thrown.');
  1764. }
  1765. public function testGetValueFromFieldDescriptionWithNoValueException()
  1766. {
  1767. $object = new \stdClass();
  1768. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  1769. $fieldDescription->expects($this->any())
  1770. ->method('getValue')
  1771. ->will($this->returnCallback(function () {
  1772. throw new NoValueException();
  1773. }));
  1774. $fieldDescription->expects($this->any())
  1775. ->method('getAssociationAdmin')
  1776. ->will($this->returnValue(null));
  1777. $this->assertSame(null, $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
  1778. }
  1779. public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance()
  1780. {
  1781. $object = new \stdClass();
  1782. $fieldDescription = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionInterface');
  1783. $fieldDescription->expects($this->any())
  1784. ->method('getValue')
  1785. ->will($this->returnCallback(function () {
  1786. throw new NoValueException();
  1787. }));
  1788. $fieldDescription->expects($this->any())
  1789. ->method('getAssociationAdmin')
  1790. ->will($this->returnValue($this->admin));
  1791. $this->admin->expects($this->once())
  1792. ->method('getNewInstance')
  1793. ->will($this->returnValue('foo'));
  1794. $this->assertSame('foo', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
  1795. }
  1796. public function testOutput()
  1797. {
  1798. $this->fieldDescription->expects($this->any())
  1799. ->method('getTemplate')
  1800. ->will($this->returnValue('SonataAdminBundle:CRUD:base_list_field.html.twig'));
  1801. $this->fieldDescription->expects($this->any())
  1802. ->method('getFieldName')
  1803. ->will($this->returnValue('fd_name'));
  1804. $this->environment->disableDebug();
  1805. $parameters = array(
  1806. 'admin' => $this->admin,
  1807. 'value' => 'foo',
  1808. 'field_description' => $this->fieldDescription,
  1809. 'object' => $this->object,
  1810. );
  1811. $template = $this->environment->loadTemplate('SonataAdminBundle:CRUD:base_list_field.html.twig');
  1812. $this->assertSame(
  1813. '<td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>',
  1814. $this->removeExtraWhitespace($this->twigExtension->output(
  1815. $this->fieldDescription,
  1816. $template,
  1817. $parameters,
  1818. $this->environment
  1819. ))
  1820. );
  1821. $this->environment->enableDebug();
  1822. $this->assertSame(
  1823. $this->removeExtraWhitespace(<<<'EOT'
  1824. <!-- START
  1825. fieldName: fd_name
  1826. template: SonataAdminBundle:CRUD:base_list_field.html.twig
  1827. compiled template: SonataAdminBundle:CRUD:base_list_field.html.twig
  1828. -->
  1829. <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
  1830. <!-- END - fieldName: fd_name -->
  1831. EOT
  1832. ),
  1833. $this->removeExtraWhitespace(
  1834. $this->twigExtension->output($this->fieldDescription, $template, $parameters, $this->environment)
  1835. )
  1836. );
  1837. }
  1838. public function testRenderRelationElementNoObject()
  1839. {
  1840. $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
  1841. }
  1842. public function testRenderRelationElementToString()
  1843. {
  1844. $this->fieldDescription->expects($this->exactly(2))
  1845. ->method('getOption')
  1846. ->will($this->returnCallback(function ($value, $default = null) {
  1847. if ($value == 'associated_property') {
  1848. return $default;
  1849. }
  1850. }));
  1851. $element = new FooToString();
  1852. $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
  1853. }
  1854. /**
  1855. * @group legacy
  1856. */
  1857. public function testDeprecatedRelationElementToString()
  1858. {
  1859. $this->fieldDescription->expects($this->exactly(2))
  1860. ->method('getOption')
  1861. ->will($this->returnCallback(function ($value, $default = null) {
  1862. if ($value == 'associated_tostring') {
  1863. return '__toString';
  1864. }
  1865. }));
  1866. $element = new FooToString();
  1867. $this->assertSame(
  1868. 'salut',
  1869. $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
  1870. );
  1871. }
  1872. /**
  1873. * @group legacy
  1874. */
  1875. public function testRenderRelationElementCustomToString()
  1876. {
  1877. $this->fieldDescription->expects($this->exactly(2))
  1878. ->method('getOption')
  1879. ->will($this->returnCallback(function ($value, $default = null) {
  1880. if ($value == 'associated_property') {
  1881. return $default;
  1882. }
  1883. if ($value == 'associated_tostring') {
  1884. return 'customToString';
  1885. }
  1886. }));
  1887. $element = $this->getMock('stdClass', array('customToString'));
  1888. $element->expects($this->any())
  1889. ->method('customToString')
  1890. ->will($this->returnValue('fooBar'));
  1891. $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
  1892. }
  1893. /**
  1894. * @group legacy
  1895. */
  1896. public function testRenderRelationElementMethodNotExist()
  1897. {
  1898. $this->fieldDescription->expects($this->exactly(2))
  1899. ->method('getOption')
  1900. ->will($this->returnCallback(function ($value, $default = null) {
  1901. if ($value == 'associated_tostring') {
  1902. return 'nonExistedMethod';
  1903. }
  1904. }));
  1905. $element = new \stdClass();
  1906. try {
  1907. $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
  1908. } catch (\RuntimeException $e) {
  1909. $this->assertContains(
  1910. 'You must define an `associated_property` option or create a `stdClass::__toString',
  1911. $e->getMessage()
  1912. );
  1913. return;
  1914. }
  1915. $this->fail('Failed asserting that exception of type "\RuntimeException" is thrown.');
  1916. }
  1917. public function testRenderRelationElementWithPropertyPath()
  1918. {
  1919. $this->fieldDescription->expects($this->exactly(1))
  1920. ->method('getOption')
  1921. ->will($this->returnCallback(function ($value, $default = null) {
  1922. if ($value == 'associated_property') {
  1923. return 'foo';
  1924. }
  1925. }));
  1926. $element = new \stdClass();
  1927. $element->foo = 'bar';
  1928. $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
  1929. }
  1930. public function testRenderRelationElementWithClosure()
  1931. {
  1932. $this->fieldDescription->expects($this->exactly(1))
  1933. ->method('getOption')
  1934. ->will($this->returnCallback(function ($value, $default = null) {
  1935. if ($value == 'associated_property') {
  1936. return function ($element) {
  1937. return 'closure '.$element->foo;
  1938. };
  1939. }
  1940. }));
  1941. $element = new \stdClass();
  1942. $element->foo = 'bar';
  1943. $this->assertSame(
  1944. 'closure bar',
  1945. $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
  1946. );
  1947. }
  1948. public function testGetUrlsafeIdentifier()
  1949. {
  1950. $entity = new \stdClass();
  1951. // set admin to pool
  1952. $this->pool->setAdminServiceIds(array('sonata_admin_foo_service'));
  1953. $this->pool->setAdminClasses(array('stdClass' => array('sonata_admin_foo_service')));
  1954. $this->admin->expects($this->once())
  1955. ->method('getUrlsafeIdentifier')
  1956. ->with($this->equalTo($entity))
  1957. ->will($this->returnValue(1234567));
  1958. $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
  1959. }
  1960. public function testGetUrlsafeIdentifier_GivenAdmin_Foo()
  1961. {
  1962. $entity = new \stdClass();
  1963. // set admin to pool
  1964. $this->pool->setAdminServiceIds(array(
  1965. 'sonata_admin_foo_service',
  1966. 'sonata_admin_bar_service',
  1967. ));
  1968. $this->pool->setAdminClasses(array('stdClass' => array(
  1969. 'sonata_admin_foo_service',
  1970. 'sonata_admin_bar_service',
  1971. )));
  1972. $this->admin->expects($this->once())
  1973. ->method('getUrlsafeIdentifier')
  1974. ->with($this->equalTo($entity))
  1975. ->will($this->returnValue(1234567));
  1976. $this->adminBar->expects($this->never())
  1977. ->method('getUrlsafeIdentifier');
  1978. $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
  1979. }
  1980. public function testGetUrlsafeIdentifier_GivenAdmin_Bar()
  1981. {
  1982. $entity = new \stdClass();
  1983. // set admin to pool
  1984. $this->pool->setAdminServiceIds(array('sonata_admin_foo_service', 'sonata_admin_bar_service'));
  1985. $this->pool->setAdminClasses(array('stdClass' => array(
  1986. 'sonata_admin_foo_service',
  1987. 'sonata_admin_bar_service',
  1988. )));
  1989. $this->admin->expects($this->never())
  1990. ->method('getUrlsafeIdentifier');
  1991. $this->adminBar->expects($this->once())
  1992. ->method('getUrlsafeIdentifier')
  1993. ->with($this->equalTo($entity))
  1994. ->will($this->returnValue(1234567));
  1995. $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
  1996. }
  1997. /**
  1998. * This method generates url part for Twig layout. Allows to keep BC for PHP 5.3.
  1999. *
  2000. * Remove this method for next major release only if PHP 5.3 support will be dropped.
  2001. *
  2002. * @param array $url
  2003. *
  2004. * @return string
  2005. */
  2006. private function buildTwigLikeUrl($url)
  2007. {
  2008. if (defined('PHP_QUERY_RFC3986')) {
  2009. // add htmlspecialchars because twig add it auto
  2010. return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
  2011. }
  2012. return htmlspecialchars(http_build_query($url, '', '&'));
  2013. }
  2014. private function removeExtraWhitespace($string)
  2015. {
  2016. return trim(preg_replace(
  2017. '/\s+/',
  2018. ' ',
  2019. $string
  2020. ));
  2021. }
  2022. }