ExtensionCompilerPassTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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\DependencyInjection;
  11. use Sonata\AdminBundle\Admin\AbstractAdmin;
  12. use Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass;
  13. use Sonata\AdminBundle\DependencyInjection\SonataAdminExtension;
  14. use Symfony\Component\DependencyInjection\ContainerBuilder;
  15. class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
  16. {
  17. /** @var SonataAdminExtension $extension */
  18. private $extension;
  19. /** @var array $config */
  20. private $config;
  21. private $publishExtension;
  22. private $historyExtension;
  23. private $orderExtension;
  24. private $securityExtension;
  25. private $filterExtension;
  26. private $timestampExtension;
  27. private $hasTraits;
  28. /**
  29. * Root name of the configuration.
  30. *
  31. * @var string
  32. */
  33. private $root;
  34. public function setUp()
  35. {
  36. $this->extension = new SonataAdminExtension();
  37. $this->config = $this->getConfig();
  38. $this->root = 'sonata.admin';
  39. $this->hasTraits = version_compare(PHP_VERSION, '5.4.0', '>=');
  40. $this->publishExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  41. $this->historyExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  42. $this->orderExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  43. $this->securityExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  44. $this->filterExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  45. $this->timestampExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
  46. }
  47. /**
  48. * @covers \Sonata\AdminBundle\DependencyInjection\SonataAdminExtension::load
  49. */
  50. public function testAdminExtensionLoad()
  51. {
  52. $this->extension->load(array(), $container = $this->getContainer());
  53. $this->assertTrue($container->hasParameter($this->root.'.extension.map'));
  54. $this->assertTrue(is_array($extensionMap = $container->getParameter($this->root.'.extension.map')));
  55. $this->assertArrayHasKey('admins', $extensionMap);
  56. $this->assertArrayHasKey('excludes', $extensionMap);
  57. $this->assertArrayHasKey('implements', $extensionMap);
  58. $this->assertArrayHasKey('extends', $extensionMap);
  59. $this->assertArrayHasKey('instanceof', $extensionMap);
  60. $this->assertArrayHasKey('uses', $extensionMap);
  61. }
  62. /**
  63. * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::flattenExtensionConfiguration
  64. */
  65. public function testFlattenEmptyExtensionConfiguration()
  66. {
  67. $this->extension->load(array(), $container = $this->getContainer());
  68. $extensionMap = $container->getParameter($this->root.'.extension.map');
  69. $method = new \ReflectionMethod(
  70. 'Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass', 'flattenExtensionConfiguration'
  71. );
  72. $method->setAccessible(true);
  73. $extensionMap = $method->invokeArgs(new ExtensionCompilerPass(), array($extensionMap));
  74. $this->assertArrayHasKey('admins', $extensionMap);
  75. $this->assertArrayHasKey('excludes', $extensionMap);
  76. $this->assertArrayHasKey('implements', $extensionMap);
  77. $this->assertArrayHasKey('extends', $extensionMap);
  78. $this->assertArrayHasKey('instanceof', $extensionMap);
  79. $this->assertArrayHasKey('uses', $extensionMap);
  80. $this->assertEmpty($extensionMap['admins']);
  81. $this->assertEmpty($extensionMap['excludes']);
  82. $this->assertEmpty($extensionMap['implements']);
  83. $this->assertEmpty($extensionMap['extends']);
  84. $this->assertEmpty($extensionMap['instanceof']);
  85. $this->assertEmpty($extensionMap['uses']);
  86. }
  87. /**
  88. * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::flattenExtensionConfiguration
  89. */
  90. public function testFlattenExtensionConfiguration()
  91. {
  92. $config = $this->getConfig();
  93. $this->extension->load(array($config), $container = $this->getContainer());
  94. $extensionMap = $container->getParameter($this->root.'.extension.map');
  95. $method = new \ReflectionMethod(
  96. 'Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass', 'flattenExtensionConfiguration'
  97. );
  98. $method->setAccessible(true);
  99. $extensionMap = $method->invokeArgs(new ExtensionCompilerPass(), array($extensionMap));
  100. // Admins
  101. $this->assertArrayHasKey('admins', $extensionMap);
  102. $this->assertCount(1, $extensionMap['admins']);
  103. $this->assertContains('sonata_extension_publish', $extensionMap['admins']['sonata_post_admin']);
  104. $this->assertCount(1, $extensionMap['admins']['sonata_post_admin']);
  105. // Excludes
  106. $this->assertArrayHasKey('excludes', $extensionMap);
  107. $this->assertCount(2, $extensionMap['excludes']);
  108. $this->assertArrayHasKey('sonata_article_admin', $extensionMap['excludes']);
  109. $this->assertCount(1, $extensionMap['excludes']['sonata_article_admin']);
  110. $this->assertContains('sonata_extension_history', $extensionMap['excludes']['sonata_article_admin']);
  111. $this->assertArrayHasKey('sonata_post_admin', $extensionMap['excludes']);
  112. $this->assertCount(1, $extensionMap['excludes']['sonata_post_admin']);
  113. $this->assertContains('sonata_extension_order', $extensionMap['excludes']['sonata_post_admin']);
  114. // Implements
  115. $this->assertArrayHasKey('implements', $extensionMap);
  116. $this->assertCount(1, $extensionMap['implements']);
  117. $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Publishable', $extensionMap['implements']);
  118. $this->assertCount(2, $extensionMap['implements']['Sonata\AdminBundle\Tests\DependencyInjection\Publishable']);
  119. $this->assertContains('sonata_extension_publish', $extensionMap['implements']['Sonata\AdminBundle\Tests\DependencyInjection\Publishable']);
  120. $this->assertContains('sonata_extension_order', $extensionMap['implements']['Sonata\AdminBundle\Tests\DependencyInjection\Publishable']);
  121. // Extends
  122. $this->assertArrayHasKey('extends', $extensionMap);
  123. $this->assertCount(1, $extensionMap['extends']);
  124. $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Post', $extensionMap['extends']);
  125. $this->assertCount(1, $extensionMap['extends']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
  126. $this->assertContains('sonata_extension_order', $extensionMap['extends']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
  127. // Instanceof
  128. $this->assertArrayHasKey('instanceof', $extensionMap);
  129. $this->assertCount(1, $extensionMap['instanceof']);
  130. $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Post', $extensionMap['instanceof']);
  131. $this->assertCount(1, $extensionMap['instanceof']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
  132. $this->assertContains('sonata_extension_history', $extensionMap['instanceof']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
  133. // Uses
  134. $this->assertArrayHasKey('uses', $extensionMap);
  135. if ($this->hasTraits) {
  136. $this->assertCount(1, $extensionMap['uses']);
  137. $this->assertArrayHasKey('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait', $extensionMap['uses']);
  138. $this->assertCount(1, $extensionMap['uses']['Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait']);
  139. $this->assertContains('sonata_extension_post', $extensionMap['uses']['Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait']);
  140. } else {
  141. $this->assertCount(0, $extensionMap['uses']);
  142. $this->assertArrayNotHasKey('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait', $extensionMap['uses']);
  143. }
  144. }
  145. /**
  146. * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
  147. * @expectedException \InvalidArgumentException
  148. */
  149. public function testProcessWithInvalidExtensionId()
  150. {
  151. $config = array(
  152. 'extensions' => array(
  153. 'sonata_extension_unknown' => array(
  154. 'excludes' => array('sonata_article_admin'),
  155. 'instanceof' => array('Sonata\AdminBundle\Tests\DependencyInjection\Post'),
  156. ),
  157. ),
  158. );
  159. $container = $this->getContainer();
  160. $this->extension->load(array($config), $container);
  161. $extensionsPass = new ExtensionCompilerPass();
  162. $extensionsPass->process($container);
  163. $container->compile();
  164. }
  165. /**
  166. * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
  167. */
  168. public function testProcessWithInvalidAdminId()
  169. {
  170. $config = array(
  171. 'extensions' => array(
  172. 'sonata_extension_publish' => array(
  173. 'admins' => array('sonata_unknown_admin'),
  174. 'implements' => array('Sonata\AdminBundle\Tests\DependencyInjection\Publishable'),
  175. ),
  176. ),
  177. );
  178. $container = $this->getContainer();
  179. $this->extension->load(array($config), $container);
  180. $extensionsPass = new ExtensionCompilerPass();
  181. $extensionsPass->process($container);
  182. $container->compile();
  183. // nothing should fail the extension just isn't added to the 'sonata_unknown_admin'
  184. }
  185. /**
  186. * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
  187. */
  188. public function testProcess()
  189. {
  190. $container = $this->getContainer();
  191. $this->extension->load(array($this->config), $container);
  192. $extensionsPass = new ExtensionCompilerPass();
  193. $extensionsPass->process($container);
  194. $container->compile();
  195. $this->assertTrue($container->hasDefinition('sonata_extension_publish'));
  196. $this->assertTrue($container->hasDefinition('sonata_extension_history'));
  197. $this->assertTrue($container->hasDefinition('sonata_extension_order'));
  198. $this->assertTrue($container->hasDefinition('sonata_extension_security'));
  199. $this->assertTrue($container->hasDefinition('sonata_extension_timestamp'));
  200. $this->assertTrue($container->hasDefinition('sonata_post_admin'));
  201. $this->assertTrue($container->hasDefinition('sonata_article_admin'));
  202. $this->assertTrue($container->hasDefinition('sonata_news_admin'));
  203. $def = $container->get('sonata_post_admin');
  204. $extensions = $def->getExtensions();
  205. $this->assertCount(4, $extensions);
  206. $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
  207. $this->assertInstanceOf(get_class($this->publishExtension), $extensions[2]);
  208. $this->assertInstanceOf(get_class($this->historyExtension), $extensions[3]);
  209. $def = $container->get('sonata_article_admin');
  210. $extensions = $def->getExtensions();
  211. $this->assertCount(5, $extensions);
  212. $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
  213. $this->assertInstanceOf(get_class($this->publishExtension), $extensions[1]);
  214. $this->assertInstanceOf(get_class($this->orderExtension), $extensions[3]);
  215. $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
  216. $def = $container->get('sonata_news_admin');
  217. $extensions = $def->getExtensions();
  218. $this->assertCount(5, $extensions);
  219. $this->assertInstanceOf(get_class($this->securityExtension), $extensions[0]);
  220. $this->assertInstanceOf(get_class($this->orderExtension), $extensions[1]);
  221. $this->assertInstanceOf(get_class($this->historyExtension), $extensions[3]);
  222. $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
  223. }
  224. public function testProcessThrowsExceptionIfTraitsAreNotAvailable()
  225. {
  226. if (!$this->hasTraits) {
  227. $this->setExpectedException('\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', 'PHP >= 5.4.0 is required to use traits.');
  228. }
  229. $config = array(
  230. 'extensions' => array(
  231. 'sonata_extension_post' => array(
  232. 'uses' => array('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait'),
  233. ),
  234. ),
  235. );
  236. $container = $this->getContainer();
  237. $this->extension->load(array($config), $container);
  238. $extensionsPass = new ExtensionCompilerPass();
  239. $extensionsPass->process($container);
  240. $container->compile();
  241. }
  242. /**
  243. * @return array
  244. */
  245. protected function getConfig()
  246. {
  247. $config = array(
  248. 'extensions' => array(
  249. 'sonata_extension_publish' => array(
  250. 'admins' => array('sonata_post_admin'),
  251. 'implements' => array('Sonata\AdminBundle\Tests\DependencyInjection\Publishable'),
  252. ),
  253. 'sonata_extension_history' => array(
  254. 'excludes' => array('sonata_article_admin'),
  255. 'instanceof' => array('Sonata\AdminBundle\Tests\DependencyInjection\Post'),
  256. ),
  257. 'sonata_extension_order' => array(
  258. 'excludes' => array('sonata_post_admin'),
  259. 'extends' => array('Sonata\AdminBundle\Tests\DependencyInjection\Post'),
  260. 'implements' => array('Sonata\AdminBundle\Tests\DependencyInjection\Publishable'),
  261. ),
  262. ),
  263. );
  264. if ($this->hasTraits) {
  265. $config['extensions']['sonata_extension_post']['uses'] = array('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait');
  266. }
  267. return $config;
  268. }
  269. private function getContainer()
  270. {
  271. $container = new ContainerBuilder();
  272. $container->setParameter('kernel.bundles', array(
  273. 'SonataCoreBundle' => true,
  274. 'KnpMenuBundle' => true,
  275. ));
  276. $container->setParameter('kernel.cache_dir', '/tmp');
  277. $container->setParameter('kernel.debug', true);
  278. // Add dependencies for SonataAdminBundle (these services will never get called so dummy classes will do)
  279. $container
  280. ->register('twig')
  281. ->setClass('Symfony\Bundle\FrameworkBundle\Templating\EngineInterface');
  282. $container
  283. ->register('templating')
  284. ->setClass('Symfony\Bundle\FrameworkBundle\Templating\EngineInterface');
  285. $container
  286. ->register('translator')
  287. ->setClass('Symfony\Bundle\FrameworkBundle\Translation\TranslatorInterface');
  288. $container
  289. ->register('validator.validator_factory')
  290. ->setClass('Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory');
  291. $container
  292. ->register('router')
  293. ->setClass('Symfony\Component\Routing\RouterInterface');
  294. $container
  295. ->register('property_accessor')
  296. ->setClass('Symfony\Component\PropertyAccess\PropertyAccessor');
  297. $container
  298. ->register('form.factory')
  299. ->setClass('Symfony\Component\Form\FormFactoryInterface');
  300. $container
  301. ->register('validator')
  302. ->setClass('Symfony\Component\Validator\ValidatorInterface');
  303. $container
  304. ->register('knp_menu.factory')
  305. ->setClass('Knp\Menu\FactoryInterface');
  306. $container
  307. ->register('knp_menu.matcher')
  308. ->setClass('Knp\Menu\Matcher\MatcherInterface');
  309. $container
  310. ->register('knp_menu.menu_provider')
  311. ->setClass('Knp\Menu\Provider\MenuProviderInterface');
  312. // Add admin definition's
  313. $container
  314. ->register('sonata_post_admin')
  315. ->setClass('Sonata\AdminBundle\Tests\DependencyInjection\MockAdmin')
  316. ->setArguments(array('', 'Sonata\AdminBundle\Tests\DependencyInjection\Post', 'SonataAdminBundle:CRUD'))
  317. ->addTag('sonata.admin');
  318. $container
  319. ->register('sonata_news_admin')
  320. ->setClass('Sonata\AdminBundle\Tests\DependencyInjection\MockAdmin')
  321. ->setArguments(array('', 'Sonata\AdminBundle\Tests\DependencyInjection\News', 'SonataAdminBundle:CRUD'))
  322. ->addTag('sonata.admin');
  323. $container
  324. ->register('sonata_article_admin')
  325. ->setClass('Sonata\AdminBundle\Tests\DependencyInjection\MockAdmin')
  326. ->setArguments(array('', 'Sonata\AdminBundle\Tests\DependencyInjection\Article', 'SonataAdminBundle:CRUD'))
  327. ->addTag('sonata.admin');
  328. $container
  329. ->register('event_dispatcher')
  330. ->setClass('Symfony\Component\EventDispatcher\EventDispatcher');
  331. // Add admin extension definition's
  332. $container
  333. ->register('sonata_extension_publish')
  334. ->setClass(get_class($this->publishExtension));
  335. $container
  336. ->register('sonata_extension_history')
  337. ->setClass(get_class($this->historyExtension));
  338. $container
  339. ->register('sonata_extension_order')
  340. ->setClass(get_class($this->orderExtension));
  341. $container
  342. ->register('sonata_extension_timestamp')
  343. ->setClass(get_class($this->timestampExtension));
  344. $container
  345. ->register('sonata_extension_security')
  346. ->setClass(get_class($this->securityExtension))
  347. ->addTag('sonata.admin.extension', array('global' => true));
  348. $container
  349. ->register('sonata_extension_filter')
  350. ->setClass(get_class($this->filterExtension))
  351. ->addTag('sonata.admin.extension', array('target' => 'sonata_news_admin'))
  352. ->addTag('sonata.admin.extension', array('target' => 'sonata_article_admin'));
  353. return $container;
  354. }
  355. }
  356. class MockAdmin extends AbstractAdmin
  357. {
  358. }
  359. class Post
  360. {
  361. }
  362. interface Publishable
  363. {
  364. }
  365. class News extends Post
  366. {
  367. }
  368. class Article implements Publishable
  369. {
  370. }