1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @file |
5
|
|
|
* Contains \Drupal\service_container\DependencyInjection\ContainerBuilder |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace Drupal\service_container\DependencyInjection; |
9
|
|
|
|
10
|
|
|
use Drupal\Component\Plugin\PluginManagerInterface; |
11
|
|
|
use Drupal\Component\Utility\NestedArray; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* ContainerBuilder retrieves container definitions from service providers to |
15
|
|
|
* build a Container. |
16
|
|
|
* |
17
|
|
|
* @ingroup dic |
18
|
|
|
*/ |
19
|
|
|
class ContainerBuilder implements ContainerBuilderInterface { |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* The plugin manager that provides the service definition providers. |
23
|
|
|
* |
24
|
|
|
* @var PluginManagerInterface |
25
|
|
|
*/ |
26
|
|
|
protected $serviceProviderManager; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* The container class to instantiate. |
30
|
|
|
* |
31
|
|
|
* To override this, use a service called container and set a class |
32
|
|
|
* attribute. |
33
|
|
|
*/ |
34
|
|
|
protected $containerClass = '\Drupal\service_container\DependencyInjection\Container'; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Constructs a ContainerBuilder object. |
38
|
|
|
* |
39
|
|
|
* @param PluginManagerInterface $service_provider_manager |
40
|
|
|
* The service provider manager that provides the service providers, |
41
|
|
|
* which define the services used in the container. |
42
|
|
|
*/ |
43
|
|
|
public function __construct(PluginManagerInterface $service_provider_manager) { |
44
|
|
|
$this->serviceProviderManager = $service_provider_manager; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritdoc} |
49
|
|
|
*/ |
50
|
|
|
public function getContainerDefinition() { |
51
|
|
|
$definitions = $this->serviceProviderManager->getDefinitions(); |
52
|
|
|
$container_definition = array(); |
53
|
|
|
$service_providers = array(); |
54
|
|
|
|
55
|
|
|
// Populate service providers. |
56
|
|
|
foreach ($definitions as $plugin_id => $definition) { |
57
|
|
|
$service_providers[$plugin_id] = $this->serviceProviderManager->createInstance($plugin_id); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
// Get container definition of each service provider and merge them. |
61
|
|
|
foreach ($definitions as $plugin_id => $definition) { |
62
|
|
|
$service_provider = $service_providers[$plugin_id]; |
63
|
|
|
$container_definition = NestedArray::mergeDeep($container_definition, $service_provider->getContainerDefinition()); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$container_definition += array( |
67
|
|
|
'services' => array(), |
68
|
|
|
'parameters' => array(), |
69
|
|
|
); // @codeCoverageIgnore |
70
|
|
|
|
71
|
|
|
// Find and setup tags for container altering. |
72
|
|
|
$container_definition['tags'] = array(); |
73
|
|
|
|
74
|
|
|
// Setup the tags structure. |
75
|
|
|
foreach ($container_definition['services'] as $service => $definition) { |
76
|
|
|
if (isset($definition['tags'])) { |
77
|
|
View Code Duplication |
foreach ($definition['tags'] as $tag) { |
|
|
|
|
78
|
|
|
$tag_name = $tag['name']; |
79
|
|
|
unset($tag['name']); |
80
|
|
|
$container_definition['tags'][$tag_name][$service][] = $tag; |
81
|
|
|
} |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
// Ensure container definition can be altered. |
86
|
|
|
foreach ($definitions as $plugin_id => $definition) { |
87
|
|
|
$service_provider = $service_providers[$plugin_id]; |
88
|
|
|
$service_provider->alterContainerDefinition($container_definition); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
// Last give a chance for traditional modules to alter this. |
92
|
|
|
$this->moduleAlter($container_definition); |
93
|
|
|
|
94
|
|
|
// Remove the tags again, not needed for the final build of the container. |
95
|
|
|
unset($container_definition['tags']); |
96
|
|
|
|
97
|
|
|
return $container_definition; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* {@inheritdoc} |
102
|
|
|
*/ |
103
|
|
|
public function compile() { |
104
|
|
|
$definition = $this->getContainerDefinition(); |
105
|
|
|
|
106
|
|
|
if (!empty($definition['services']['service_container']['class'])) { |
107
|
|
|
$this->containerClass = $definition['services']['service_container']['class']; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
return new $this->containerClass($definition); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Provides class based version of drupal_alter() to allow testing. |
115
|
|
|
* |
116
|
|
|
* This function must be mocked for unit tests. |
117
|
|
|
* |
118
|
|
|
* Note: Only the container builder needs this, other classes should |
119
|
|
|
* use the ModuleHandler within the container. |
120
|
|
|
* |
121
|
|
|
* @param $container_definition |
122
|
|
|
* The fully build container definition that can be altered by modules now. |
123
|
|
|
* |
124
|
|
|
* @codeCoverageIgnore |
125
|
|
|
*/ |
126
|
|
|
protected function moduleAlter(&$container_definition) { |
127
|
|
|
drupal_alter('service_container_container_build', $container_definition); |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.