Completed
Push — master ( aaeda7...30c0e6 )
by Olivier
02:00
created

ContainerProxy   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
lcom 1
cbo 8
dl 0
loc 185
rs 10
c 1
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A get_container() 0 4 2
A __construct() 0 5 1
A __invoke() 0 4 1
A instantiate_container() 0 22 3
A create_container() 0 12 1
A apply_extensions() 0 15 3
A collect_extensions() 0 12 2
A apply_services() 0 16 3
A collect_services() 0 18 3
A dump_container() 0 6 1
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie\Binding\SymfonyDependencyInjection;
13
14
use ICanBoogie\Accessor\AccessorTrait;
15
use ICanBoogie\Application;
16
use ICanBoogie\Autoconfig\Autoconfig;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\Container;
19
use Symfony\Component\DependencyInjection\ContainerBuilder;
20
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
21
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
22
23
/**
24
 * Proxy to Symfony container.
25
 *
26
 * @property-read Container $container
27
 */
28
class ContainerProxy
29
{
30
	use AccessorTrait;
31
32
	const SERVICE_APP = 'app';
33
	const SERVICE_CONTAINER = 'container';
34
	const CONFIG_FILENAME = 'services.yml';
35
36
	/**
37
	 * @var Application
38
	 */
39
	private $app;
40
41
	/**
42
	 * @var array
43
	 */
44
	private $config = [];
45
46
	/**
47
	 * @var Container
48
	 */
49
	private $container;
50
51
	/**
52
	 * @return Container
53
	 */
54
	protected function get_container()
55
	{
56
		return $this->container ?: $this->container = $this->instantiate_container();
57
	}
58
59
	/**
60
	 * @codeCoverageIgnoreStart
61
	 *
62
	 * @param Application $app
63
	 * @param array $config
64
	 */
65
	public function __construct(Application $app, array $config)
66
	{
67
		$this->app = $app;
68
		$this->config = ContainerConfig::normalize($config);
69
	}
70
	// @codeCoverageIgnoreEnd
71
72
	/**
73
	 * @param string $id Service identifier
74
	 *
75
	 * @return object
76
	 */
77
	public function __invoke($id)
78
	{
79
		return $this->get_container()->get($id);
80
	}
81
82
	/**
83
	 * @return ContainerBuilder
84
	 */
85
	private function instantiate_container()
86
	{
87
		$app = $this->app;
88
		$class = 'ApplicationContainer';
89
		$pathname = ContainerPathname::from($app);
90
91
		if (!$this->config[ContainerConfig::USE_CACHING] || !file_exists($pathname))
92
		{
93
			$container = $this->create_container();
94
			$this->dump_container($container, $pathname, $class);
95
		}
96
97
		require $pathname;
98
99
		/* @var $container ContainerBuilder */
100
101
		$container = new $class();
102
		$container->set(self::SERVICE_APP, $app);
103
		$container->set(self::SERVICE_CONTAINER, $container);
104
105
		return $container;
106
	}
107
108
	/**
109
	 * @return ContainerBuilder
110
	 */
111
	private function create_container()
112
	{
113
		$container = new ContainerBuilder();
114
115
		$this->apply_extensions($container);
116
		$this->apply_services($container);
117
118
		$container->compile();
119
		$container->set(self::SERVICE_APP, $this->app);
120
121
		return $container;
122
	}
123
124
	/**
125
	 * @param ContainerBuilder $container
126
	 */
127
	private function apply_extensions(ContainerBuilder $container)
128
	{
129
		$extensions = $this->collect_extensions();
130
131
		if (!$extensions)
132
		{
133
			return; // @codeCoverageIgnore
134
		}
135
136
		foreach ($extensions as $extension)
137
		{
138
			$container->registerExtension($extension);
139
			$container->loadFromExtension($extension->getAlias());
140
		}
141
	}
142
143
	/**
144
	 * @return array
145
	 */
146
	private function collect_extensions()
147
	{
148
		$app = $this->app;
149
		$extensions = [];
150
151
		foreach ($this->config[ContainerConfig::EXTENSIONS] as $constructor)
152
		{
153
			$extensions[] = $constructor($app, $this);
154
		}
155
156
		return $extensions;
157
	}
158
159
	/**
160
	 * @param ContainerBuilder $container
161
	 */
162
	private function apply_services(ContainerBuilder $container)
163
	{
164
		$collection = $this->collect_services();
165
166
		if (!$collection)
167
		{
168
			return; // @codeCoverageIgnore
169
		}
170
171
		$loader = new YamlFileLoader($container, new FileLocator(getcwd()));
172
173
		foreach ($collection as $service_pathname)
174
		{
175
			$loader->load($service_pathname);
176
		}
177
	}
178
179
	/**
180
	 * @return array
181
	 */
182
	private function collect_services()
183
	{
184
		$collection = [];
185
186
		foreach (array_keys($this->app->config[Autoconfig::CONFIG_PATH]) as $path)
187
		{
188
			$pathname = $path . DIRECTORY_SEPARATOR . self::CONFIG_FILENAME;
189
190
			if (!file_exists($pathname))
191
			{
192
				continue;
193
			}
194
195
			$collection[] = $pathname;
196
		}
197
198
		return $collection;
199
	}
200
201
	/**
202
	 * @param ContainerBuilder $container
203
	 * @param ContainerPathname $pathname
204
	 * @param string $class
205
	 */
206
	private function dump_container(ContainerBuilder $container, ContainerPathname $pathname, $class)
207
	{
208
		$dumper = new PhpDumper($container);
209
210
		file_put_contents($pathname, $dumper->dump([ 'class' => $class ]));
211
	}
212
}
213