ResolveDefinitionTemplatesPass.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. namespace Symfony\Component\DependencyInjection\Compiler;
  3. use Symfony\Component\DependencyInjection\Definition;
  4. use Symfony\Component\DependencyInjection\DefinitionDecorator;
  5. use Symfony\Component\DependencyInjection\ContainerBuilder;
  6. /**
  7. * This replaces all DefinitionDecorator instances with their equivalent fully
  8. * merged Definition instance.
  9. *
  10. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  11. */
  12. class ResolveDefinitionTemplatesPass implements CompilerPassInterface
  13. {
  14. private $container;
  15. private $compiler;
  16. private $formatter;
  17. /**
  18. * Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
  19. *
  20. * @param ContainerBuilder $container
  21. */
  22. public function process(ContainerBuilder $container)
  23. {
  24. $this->container = $container;
  25. $this->compiler = $container->getCompiler();
  26. $this->formatter = $this->compiler->getLoggingFormatter();
  27. foreach (array_keys($container->getDefinitions()) as $id) {
  28. // yes, we are specifically fetching the definition from the
  29. // container to ensure we are not operating on stale data
  30. $definition = $container->getDefinition($id);
  31. if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
  32. continue;
  33. }
  34. $this->resolveDefinition($id, $definition);
  35. }
  36. }
  37. /**
  38. * Resolves the definition
  39. *
  40. * @param string $id The definition identifier
  41. * @param DefinitionDecorator $definition
  42. * @return Definition
  43. */
  44. private function resolveDefinition($id, DefinitionDecorator $definition)
  45. {
  46. if (!$this->container->hasDefinition($parent = $definition->getParent())) {
  47. throw new \RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
  48. }
  49. $parentDef = $this->container->getDefinition($parent);
  50. if ($parentDef instanceof DefinitionDecorator) {
  51. $parentDef = $this->resolveDefinition($parent, $parentDef);
  52. }
  53. $this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
  54. $def = new Definition();
  55. // merge in parent definition
  56. // purposely ignored attributes: scope, abstract, tags
  57. $def->setClass($parentDef->getClass());
  58. $def->setArguments($parentDef->getArguments());
  59. $def->setMethodCalls($parentDef->getMethodCalls());
  60. $def->setProperties($parentDef->getProperties());
  61. $def->setFactoryClass($parentDef->getFactoryClass());
  62. $def->setFactoryMethod($parentDef->getFactoryMethod());
  63. $def->setFactoryService($parentDef->getFactoryService());
  64. $def->setConfigurator($parentDef->getConfigurator());
  65. $def->setFile($parentDef->getFile());
  66. $def->setPublic($parentDef->isPublic());
  67. // overwrite with values specified in the decorator
  68. $changes = $definition->getChanges();
  69. if (isset($changes['class'])) {
  70. $def->setClass($definition->getClass());
  71. }
  72. if (isset($changes['factory_class'])) {
  73. $def->setFactoryClass($definition->getFactoryClass());
  74. }
  75. if (isset($changes['factory_method'])) {
  76. $def->setFactoryMethod($definition->getFactoryMethod());
  77. }
  78. if (isset($changes['factory_service'])) {
  79. $def->setFactoryService($definition->getFactoryService());
  80. }
  81. if (isset($changes['configurator'])) {
  82. $def->setConfigurator($definition->getConfigurator());
  83. }
  84. if (isset($changes['file'])) {
  85. $def->setFile($definition->getFile());
  86. }
  87. if (isset($changes['public'])) {
  88. $def->setPublic($definition->isPublic());
  89. }
  90. // merge arguments
  91. foreach ($definition->getArguments() as $k => $v) {
  92. if (is_numeric($k)) {
  93. $def->addArgument($v);
  94. continue;
  95. }
  96. if (0 !== strpos($k, 'index_')) {
  97. throw new \RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
  98. }
  99. $index = (integer) substr($k, strlen('index_'));
  100. $def->setArgument($index, $v);
  101. }
  102. // merge properties
  103. foreach ($definition->getProperties() as $k => $v) {
  104. $def->setProperty($k, $v);
  105. }
  106. // append method calls
  107. if (count($calls = $definition->getMethodCalls()) > 0) {
  108. $def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
  109. }
  110. // these attributes are always taken from the child
  111. $def->setAbstract($definition->isAbstract());
  112. $def->setScope($definition->getScope());
  113. $def->setTags($definition->getTags());
  114. // set new definition on container
  115. $this->container->setDefinition($id, $def);
  116. return $def;
  117. }
  118. }