ExtensionCompilerPass.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. /*
  3. * This file is part of the Sonata project.
  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\DependencyInjection\Compiler;
  11. use Symfony\Component\DependencyInjection\Definition;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. /**
  16. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  17. */
  18. class ExtensionCompilerPass implements CompilerPassInterface
  19. {
  20. /**
  21. * {@inheritDoc}
  22. */
  23. public function process(ContainerBuilder $container)
  24. {
  25. $universalExtensions = array();
  26. foreach ($container->findTaggedServiceIds('sonata.admin.extension') as $id => $attributes) {
  27. $target = false;
  28. if (isset($attributes[0]['target'])) {
  29. $target = $attributes[0]['target'];
  30. }
  31. if (isset($attributes[0]['global']) && $attributes[0]['global']) {
  32. $universalExtensions[] = $id;
  33. }
  34. if (!$target || !$container->hasDefinition($target)) {
  35. continue;
  36. }
  37. $container->getDefinition($target)
  38. ->addMethodCall('addExtension', array(new Reference($id)));
  39. }
  40. $extensionConfig = $container->getParameter('sonata.admin.extension.map');
  41. $extensionMap = $this->flattenExtensionConfiguration($extensionConfig);
  42. foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $attributes) {
  43. $admin = $container->getDefinition($id);
  44. foreach ($universalExtensions as $extension) {
  45. $admin->addMethodCall('addExtension', array(new Reference($extension)));
  46. }
  47. $extensions = $this->getExtensionsForAdmin($id, $admin, $container, $extensionMap);
  48. foreach ($extensions as $extension) {
  49. if(!$container->hasDefinition($extension)){
  50. throw new \InvalidArgumentException(sprintf('Unable to find extension service for id %s', $extension));
  51. }
  52. $admin->addMethodCall('addExtension', array(new Reference($extension)));
  53. }
  54. }
  55. }
  56. /**
  57. * @param string $id
  58. * @param Definition $admin
  59. * @param ContainerBuilder $container
  60. * @param array $extensionMap
  61. * @return array
  62. */
  63. protected function getExtensionsForAdmin($id, Definition $admin, ContainerBuilder $container, array $extensionMap)
  64. {
  65. $extensions = array();
  66. $class = $classReflection = $subjectReflection = null;
  67. $excludes = $extensionMap['excludes'];
  68. unset($extensionMap['excludes']);
  69. foreach ($extensionMap as $type => $subjects) {
  70. foreach ($subjects as $subject => $extensionList) {
  71. if('admins' == $type){
  72. if($id == $subject){
  73. $extensions = array_merge($extensions, $extensionList);
  74. }
  75. } else {
  76. $class = $this->getManagedClass($admin, $container);
  77. $classReflection = new \ReflectionClass($class);
  78. $subjectReflection = new \ReflectionClass($subject);
  79. }
  80. if('instanceof' == $type){
  81. if($subjectReflection->getName() == $classReflection->getName() || $classReflection->isSubclassOf($subject)){
  82. $extensions = array_merge($extensions, $extensionList);
  83. }
  84. }
  85. if('implements' == $type){
  86. if($classReflection->implementsInterface($subject)){
  87. $extensions = array_merge($extensions, $extensionList);
  88. }
  89. }
  90. if('extends' == $type){
  91. if($classReflection->isSubclassOf($subject)){
  92. $extensions = array_merge($extensions, $extensionList);
  93. }
  94. }
  95. }
  96. }
  97. if(isset($excludes[$id])){
  98. $extensions = array_diff($extensions, $excludes[$id]);
  99. }
  100. return $extensions;
  101. }
  102. /**
  103. * Resolves the class argument of the admin to an actual class (in case of %parameter%)
  104. *
  105. * @param Definition $admin
  106. * @param ContainerBuilder $container
  107. * @return string
  108. */
  109. protected function getManagedClass(Definition $admin, ContainerBuilder $container)
  110. {
  111. return $container->getParameterBag()->resolveValue($admin->getArgument(1));
  112. }
  113. /**
  114. * @param array $config
  115. * @return array
  116. */
  117. protected function flattenExtensionConfiguration(array $config)
  118. {
  119. $extensionMap = array(
  120. 'excludes' => array(),
  121. 'admins' => array(),
  122. 'implements' => array(),
  123. 'extends' => array(),
  124. 'instanceof' => array(),
  125. );
  126. foreach ($config as $extension => $options) {
  127. foreach ($options as $key => $value) {
  128. foreach ($value as $source) {
  129. if(!isset($extensionMap[$key][$source])){
  130. $extensionMap[$key][$source] = array();
  131. }
  132. array_push($extensionMap[$key][$source], $extension);
  133. }
  134. }
  135. }
  136. return $extensionMap;
  137. }
  138. }