CRUDControllerTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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\Controller;
  11. use Symfony\Component\DependencyInjection\ContainerInterface;
  12. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Sonata\AdminBundle\Controller\CRUDController;
  15. use Sonata\AdminBundle\Admin\Pool;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Bridge\Twig\Extension\FormExtension;
  18. use Symfony\Component\HttpFoundation\Session\Session;
  19. use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
  20. use Sonata\AdminBundle\Exception\ModelManagerException;
  21. /**
  22. * Test for CRUDController
  23. *
  24. * @author Andrej Hudec <pulzarraider@gmail.com>
  25. */
  26. class CRUDControllerTest extends \PHPUnit_Framework_TestCase
  27. {
  28. /**
  29. * @var CRUDController
  30. */
  31. private $controller;
  32. /**
  33. * @var Request
  34. */
  35. private $request;
  36. /**
  37. * @var Sonata\AdminBundle\Admin\AdminInterface
  38. */
  39. private $admin;
  40. /**
  41. * @var Pool
  42. */
  43. private $pool;
  44. /**
  45. * @var array
  46. */
  47. private $parameters;
  48. /**
  49. *
  50. * @var Session
  51. */
  52. private $session;
  53. /**
  54. * {@inheritDoc}
  55. */
  56. protected function setUp()
  57. {
  58. $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
  59. $this->request = new Request();
  60. $this->pool = new Pool($container, 'title', 'logo.png');
  61. $this->request->attributes->set('_sonata_admin', 'foo.admin');
  62. $this->admin = $this->getMock('Sonata\AdminBundle\Admin\AdminInterface');
  63. $this->parameters = array();
  64. // php 5.3 BC
  65. $params = &$this->parameters;
  66. $templating = $this->getMock('Symfony\Bundle\FrameworkBundle\Templating\DelegatingEngine', array(), array($container, array()));
  67. $templating->expects($this->any())
  68. ->method('renderResponse')
  69. ->will($this->returnCallback(function($view, array $parameters = array(), Response $response = null) use (&$params) {
  70. if (null === $response) {
  71. $response = new Response();
  72. }
  73. $params = $parameters;
  74. return $response;
  75. }));
  76. $this->session = new Session(new MockArraySessionStorage());
  77. // php 5.3 BC
  78. $pool = $this->pool;
  79. $request = $this->request;
  80. $admin = $this->admin;
  81. $session = $this->session;
  82. $twig = $this->getMockBuilder('Twig_Environment')
  83. ->disableOriginalConstructor()
  84. ->getMock();
  85. $twigRenderer = $this->getMock('Symfony\Bridge\Twig\Form\TwigRendererInterface');
  86. $formExtension = new FormExtension($twigRenderer);
  87. $twig->expects($this->any())
  88. ->method('getExtension')
  89. ->will($this->returnCallback(function($name) use ($formExtension) {
  90. switch ($name) {
  91. case 'form':
  92. return $formExtension;
  93. }
  94. return null;
  95. }));
  96. $container->expects($this->any())
  97. ->method('get')
  98. ->will($this->returnCallback(function($id) use ($pool, $request, $admin, $templating, $twig, $session) {
  99. switch ($id) {
  100. case 'sonata.admin.pool':
  101. return $pool;
  102. case 'request':
  103. return $request;
  104. case 'foo.admin':
  105. return $admin;
  106. case 'templating':
  107. return $templating;
  108. case 'twig':
  109. return $twig;
  110. case 'session':
  111. return $session;
  112. }
  113. return null;
  114. }));
  115. $this->admin->expects($this->any())
  116. ->method('getTemplate')
  117. ->will($this->returnCallback(function($name) {
  118. switch ($name) {
  119. case 'ajax':
  120. return 'SonataAdminBundle::ajax_layout.html.twig';
  121. case 'layout':
  122. return 'SonataAdminBundle::standard_layout.html.twig';
  123. case 'show':
  124. return 'SonataAdminBundle:CRUD:show.html.twig';
  125. }
  126. return null;
  127. }));
  128. $this->admin->expects($this->any())
  129. ->method('getIdParameter')
  130. ->will($this->returnValue('id'));
  131. $this->admin->expects($this->any())
  132. ->method('generateUrl')
  133. ->will($this->returnCallback(function($name, array $parameters = array(), $absolute = false) {
  134. $result = $name;
  135. if (!empty($parameters)) {
  136. $result .= '?'.http_build_query($parameters);
  137. }
  138. return $result;
  139. }));
  140. $this->controller = new CRUDController();
  141. $this->controller->setContainer($container);
  142. }
  143. public function testRenderJson1()
  144. {
  145. $data = array('example'=>'123', 'foo'=>'bar');
  146. $this->request->headers->set('Content-Type', 'application/x-www-form-urlencoded');
  147. $response = $this->controller->renderJson($data);
  148. $this->assertEquals($response->headers->get('Content-Type'), 'application/json');
  149. $this->assertEquals(json_encode($data), $response->getContent());
  150. }
  151. public function testRenderJson2()
  152. {
  153. $data = array('example'=>'123', 'foo'=>'bar');
  154. $this->request->headers->set('Content-Type', 'multipart/form-data');
  155. $response = $this->controller->renderJson($data);
  156. $this->assertEquals($response->headers->get('Content-Type'), 'application/json');
  157. $this->assertEquals(json_encode($data), $response->getContent());
  158. }
  159. public function testRenderJsonAjax()
  160. {
  161. $data = array('example'=>'123', 'foo'=>'bar');
  162. $this->request->attributes->set('_xml_http_request', true);
  163. $this->request->headers->set('Content-Type', 'multipart/form-data');
  164. $response = $this->controller->renderJson($data);
  165. $this->assertEquals($response->headers->get('Content-Type'), 'text/plain');
  166. $this->assertEquals(json_encode($data), $response->getContent());
  167. }
  168. public function testIsXmlHttpRequest()
  169. {
  170. $this->assertFalse($this->controller->isXmlHttpRequest());
  171. $this->request->headers->set('X-Requested-With', 'XMLHttpRequest');
  172. $this->assertTrue($this->controller->isXmlHttpRequest());
  173. $this->request->headers->remove('X-Requested-With');
  174. $this->assertFalse($this->controller->isXmlHttpRequest());
  175. $this->request->attributes->set('_xml_http_request', true);
  176. $this->assertTrue($this->controller->isXmlHttpRequest());
  177. }
  178. public function testConfigureWithException()
  179. {
  180. $this->setExpectedException('RuntimeException', 'There is no `_sonata_admin` defined for the controller `Sonata\AdminBundle\Controller\CRUDController`');
  181. $this->request->attributes->remove('_sonata_admin');
  182. $this->controller->configure();
  183. }
  184. public function testConfigureWithException2()
  185. {
  186. $this->setExpectedException('RuntimeException', 'Unable to find the admin class related to the current controller (Sonata\AdminBundle\Controller\CRUDController)');
  187. $this->request->attributes->set('_sonata_admin', 'nonexistent.admin');
  188. $this->controller->configure();
  189. }
  190. public function testGetBaseTemplate()
  191. {
  192. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->controller->getBaseTemplate());
  193. $this->request->headers->set('X-Requested-With', 'XMLHttpRequest');
  194. $this->assertEquals('SonataAdminBundle::ajax_layout.html.twig', $this->controller->getBaseTemplate());
  195. $this->request->headers->remove('X-Requested-With');
  196. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->controller->getBaseTemplate());
  197. $this->request->attributes->set('_xml_http_request', true);
  198. $this->assertEquals('SonataAdminBundle::ajax_layout.html.twig', $this->controller->getBaseTemplate());
  199. }
  200. public function testRender()
  201. {
  202. $this->parameters = array();
  203. $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $this->controller->render('FooAdminBundle::foo.html.twig', array()));
  204. $this->assertEquals($this->admin, $this->parameters['admin']);
  205. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->parameters['base_template']);
  206. $this->assertEquals($this->pool, $this->parameters['admin_pool']);
  207. }
  208. public function testRenderCustomParams()
  209. {
  210. $this->parameters = array();
  211. $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $this->controller->render('FooAdminBundle::foo.html.twig', array('foo'=>'bar')));
  212. $this->assertEquals($this->admin, $this->parameters['admin']);
  213. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->parameters['base_template']);
  214. $this->assertEquals($this->pool, $this->parameters['admin_pool']);
  215. $this->assertEquals('bar', $this->parameters['foo']);
  216. }
  217. public function testRenderAjax()
  218. {
  219. $this->parameters = array();
  220. $this->request->headers->set('X-Requested-With', 'XMLHttpRequest');
  221. $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $this->controller->render('FooAdminBundle::foo.html.twig', array('foo'=>'bar')));
  222. $this->assertEquals($this->admin, $this->parameters['admin']);
  223. $this->assertEquals('SonataAdminBundle::ajax_layout.html.twig', $this->parameters['base_template']);
  224. $this->assertEquals($this->pool, $this->parameters['admin_pool']);
  225. $this->assertEquals('bar', $this->parameters['foo']);
  226. }
  227. public function testListActionAccessDenied()
  228. {
  229. $this->setExpectedException('Symfony\Component\Security\Core\Exception\AccessDeniedException');
  230. $this->admin->expects($this->once())
  231. ->method('isGranted')
  232. ->will($this->returnValue(false));
  233. $this->controller->listAction();
  234. }
  235. public function testListAction()
  236. {
  237. $datagrid = $this->getMock('Sonata\AdminBundle\Datagrid\DatagridInterface');
  238. $form = $this->getMockBuilder('Symfony\Component\Form\Form')
  239. ->disableOriginalConstructor()
  240. ->getMock();
  241. $form->expects($this->once())
  242. ->method('createView')
  243. ->will($this->returnValue($this->getMock('Symfony\Component\Form\FormView')));
  244. $this->admin->expects($this->once())
  245. ->method('getDatagrid')
  246. ->will($this->returnValue($datagrid));
  247. $datagrid->expects($this->once())
  248. ->method('getForm')
  249. ->will($this->returnValue($form));
  250. $this->parameters = array();
  251. $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $this->controller->listAction());
  252. $this->assertEquals($this->admin, $this->parameters['admin']);
  253. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->parameters['base_template']);
  254. $this->assertEquals($this->pool, $this->parameters['admin_pool']);
  255. $this->assertEquals('list', $this->parameters['action']);
  256. $this->assertInstanceOf('Symfony\Component\Form\FormView', $this->parameters['form']);
  257. $this->assertInstanceOf('Sonata\AdminBundle\Datagrid\DatagridInterface', $this->parameters['datagrid']);
  258. $this->assertEquals('', $this->parameters['csrf_token']);
  259. }
  260. public function testBatchActionDeleteAccessDenied()
  261. {
  262. $this->setExpectedException('Symfony\Component\Security\Core\Exception\AccessDeniedException');
  263. $this->admin->expects($this->once())
  264. ->method('isGranted')
  265. ->will($this->returnValue(false));
  266. $this->controller->batchActionDelete($this->getMock('Sonata\AdminBundle\Datagrid\ProxyQueryInterface'));
  267. }
  268. public function testBatchActionDelete()
  269. {
  270. $modelManager = $this->getMock('Sonata\AdminBundle\Model\ModelManagerInterface');
  271. $this->admin->expects($this->once())
  272. ->method('getModelManager')
  273. ->will($this->returnValue($modelManager));
  274. $this->admin->expects($this->once())
  275. ->method('getFilterParameters')
  276. ->will($this->returnValue(array('foo'=>'bar')));
  277. $result = $this->controller->batchActionDelete($this->getMock('Sonata\AdminBundle\Datagrid\ProxyQueryInterface'));
  278. $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result);
  279. $this->assertSame(array('flash_batch_delete_success'), $this->session->getFlashBag()->get('sonata_flash_success'));
  280. $this->assertEquals('list?filter%5Bfoo%5D=bar', $result->getTargetUrl());
  281. }
  282. public function testBatchActionDeleteWithModelManagerException()
  283. {
  284. $modelManager = $this->getMock('Sonata\AdminBundle\Model\ModelManagerInterface');
  285. $modelManager->expects($this->once())
  286. ->method('batchDelete')
  287. ->will($this->returnCallback(function() {
  288. throw new ModelManagerException();
  289. }));
  290. $this->admin->expects($this->once())
  291. ->method('getModelManager')
  292. ->will($this->returnValue($modelManager));
  293. $this->admin->expects($this->once())
  294. ->method('getFilterParameters')
  295. ->will($this->returnValue(array('foo'=>'bar')));
  296. $result = $this->controller->batchActionDelete($this->getMock('Sonata\AdminBundle\Datagrid\ProxyQueryInterface'));
  297. $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result);
  298. $this->assertSame(array('flash_batch_delete_error'), $this->session->getFlashBag()->get('sonata_flash_error'));
  299. $this->assertEquals('list?filter%5Bfoo%5D=bar', $result->getTargetUrl());
  300. }
  301. public function testShowActionNotFoundException()
  302. {
  303. $this->setExpectedException('Symfony\Component\HttpKernel\Exception\NotFoundHttpException');
  304. $this->admin->expects($this->once())
  305. ->method('getObject')
  306. ->will($this->returnValue(false));
  307. $this->controller->showAction();
  308. }
  309. public function testShowActionAccessDenied()
  310. {
  311. $this->setExpectedException('Symfony\Component\Security\Core\Exception\AccessDeniedException');
  312. $this->admin->expects($this->once())
  313. ->method('getObject')
  314. ->will($this->returnValue(new \stdClass()));
  315. $this->admin->expects($this->once())
  316. ->method('isGranted')
  317. ->will($this->returnValue(false));
  318. $this->controller->showAction();
  319. }
  320. public function testShowAction()
  321. {
  322. $object = new \stdClass();
  323. $this->admin->expects($this->once())
  324. ->method('getObject')
  325. ->will($this->returnValue($object));
  326. $this->admin->expects($this->once())
  327. ->method('isGranted')
  328. ->will($this->returnValue(true));
  329. $show = $this->getMock('Sonata\AdminBundle\Admin\FieldDescriptionCollection');
  330. $this->admin->expects($this->once())
  331. ->method('getShow')
  332. ->will($this->returnValue($show));
  333. $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $this->controller->showAction());
  334. $this->assertEquals($this->admin, $this->parameters['admin']);
  335. $this->assertEquals('SonataAdminBundle::standard_layout.html.twig', $this->parameters['base_template']);
  336. $this->assertEquals($this->pool, $this->parameters['admin_pool']);
  337. $this->assertEquals('show', $this->parameters['action']);
  338. $this->assertInstanceOf('Sonata\AdminBundle\Admin\FieldDescriptionCollection', $this->parameters['elements']);
  339. $this->assertEquals($object, $this->parameters['object']);
  340. }
  341. /**
  342. * @dataProvider getRedirectToTests
  343. */
  344. public function testRedirectTo($expected, $queryParams, $hasActiveSubclass)
  345. {
  346. $this->admin->expects($this->any())
  347. ->method('generateObjectUrl')
  348. ->will($this->returnCallback(function($name, $object, array $parameters = array(), $absolute = false) {
  349. return get_class($object).'_'.$name;
  350. }));
  351. $this->admin->expects($this->any())
  352. ->method('hasActiveSubclass')
  353. ->will($this->returnValue($hasActiveSubclass));
  354. $object = new \stdClass();
  355. foreach ($queryParams as $key => $value) {
  356. $this->request->query->set($key, $value);
  357. }
  358. $response = $this->controller->redirectTo($object);
  359. $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
  360. $this->assertEquals($expected, $response->getTargetUrl());
  361. }
  362. public function getRedirectToTests()
  363. {
  364. return array(
  365. array('stdClass_edit', array(), false),
  366. array('list', array('btn_update_and_list'=>true), false),
  367. array('list', array('btn_create_and_list'=>true), false),
  368. array('create', array('btn_create_and_create'=>true), false),
  369. array('create?subclass=foo', array('btn_create_and_create'=>true, 'subclass'=>'foo'), true),
  370. );
  371. }
  372. public function testAddFlash()
  373. {
  374. $this->controller->addFlash('foo', 'bar');
  375. $this->assertSame(array('bar'), $this->session->getFlashBag()->get('foo'));
  376. }
  377. }