Completed
Push — master ( 52d21c...db66d7 )
by Adam
02:02
created

FlysystemExtension   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 95.08%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 4
dl 0
loc 170
ccs 58
cts 61
cp 0.9508
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
B loadConfiguration() 0 46 3
B loadServices() 0 22 4
A registerService() 0 16 2
D validateParameters() 0 32 9
A register() 0 6 1
1
<?php
2
/**
3
 * FlysystemExtension.php
4
 *
5
 * @copyright      More in license.md
6
 * @license        http://www.ipublikuj.eu
7
 * @author         Adam Kadlec http://www.ipublikuj.eu
8
 * @package        iPublikuj:Flysystem!
9
 * @subpackage     DI
10
 * @since          1.0.0
11
 *
12
 * @date           05.04.16
13
 */
14
15
declare(strict_types = 1);
16
17
namespace IPub\Flysystem\DI;
18
19
use Nette;
20
use Nette\DI;
21
use Nette\Utils;
22
use Nette\PhpGenerator as Code;
23
24
use League\Flysystem;
25
26
use IPub\Flysystem\Exceptions;
27
use IPub\Flysystem\Factories;
28
use IPub\Flysystem\Loaders;
29
30
/**
31
 * Flysystem extension container
32
 *
33
 * @package        iPublikuj:Flysystem!
34
 * @subpackage     DI
35
 *
36
 * @author         Adam Kadlec <[email protected]>
37
 */
38 1
class FlysystemExtension extends DI\CompilerExtension
39
{
40
	/**
41
	 * @var array
42
	 */
43
	private $defaults = [
44
		'adapters'    => [],
45
		'cache'       => [],
46
		'filesystems' => [],
47
	];
48
49
	public function loadConfiguration() : void
50
	{
51
		/** @var DI\ContainerBuilder $builder */
52 1
		$builder = $this->getContainerBuilder();
53
		// Get extension configuration
54 1
		$configuration = $this->getConfig($this->defaults);
55
56
		// Load all configured adapters
57 1
		$this->loadServices($configuration['adapters'], 'adapters');
58
59
		// Load all configured cache systems
60 1
		$this->loadServices($configuration['cache'], 'cache');
61
62 1
		$mountManager = $builder->addDefinition($this->prefix('mountmanager'))
63 1
			->setType(Flysystem\MountManager::class);
64
65 1
		foreach ($configuration['filesystems'] as $name => $filesystem) {
66
			// Check if filesystem is with cache
67 1
			if (array_key_exists('cache', $filesystem)) {
68
				// Create adapter name
69 1
				$adapterName = 'cached_' . $filesystem['adapter'] . '_' . $filesystem['cache'] . '_' . uniqid();
70
71
				// Create cached adapter
72 1
				$this->registerService(
73 1
					'adapters',
74
					$adapterName,
75 1
					Flysystem\Cached\CachedAdapter::class,
76 1
					'IPub\Flysystem\Factories\Adapters\CachedFactory::create',
77
					[
78 1
						'adapterServiceName' => $this->prefix('adapters.' . $filesystem['adapter']),
79 1
						'cacheServiceName'   => $this->prefix('cache.' . $filesystem['cache']),
80
					]
81
				);
82
83
			} else {
84 1
				$adapterName = $filesystem['adapter'];
85
			}
86
87 1
			$builder->addDefinition($this->prefix('filesystem.' . $name))
88 1
				->setType(Flysystem\Filesystem::class)
89 1
				->setArguments(['adapter' => '@' . $this->prefix('adapters.' . $adapterName)])
90 1
				->addTag('ipub.flysystem.filesystem');
91
92 1
			$mountManager->addSetup('?->mountFilesystem(?, ?)', [$mountManager, $name, '@' . $this->prefix('filesystem.' . $name)]);
93
		}
94 1
	}
95
96
	/**
97
	 * @param array $services
98
	 * @param string $type
99
	 *
100
	 * @return void
101
	 */
102
	private function loadServices(array $services, string $type) : void
103
	{
104
		// Get neon file adapter
105 1
		$neonAdapter = new Loaders\NeonFileLoader;
106
107
		// Load adapters factories list
108 1
		$definitions = $neonAdapter->load(__DIR__ . DIRECTORY_SEPARATOR . $type . '.neon');
109
110 1
		foreach ($services as $serviceName => $configuration) {
111 1
			if (isset($configuration['type']) && array_key_exists($configuration['type'], $definitions)) {
112 1
				$service = $definitions[$configuration['type']];
113 1
				$serviceConfiguration = $this->validateParameters($service['parameters'], $configuration, $serviceName);
114
115 1
				$this->registerService($type, $serviceName, $service['class'], $service['factory'], [
116 1
					'parameters' => $serviceConfiguration,
117
				]);
118
119
			} else {
120 1
				throw new Exceptions\InvalidAdapterException(sprintf('The service "%s" is not defined in Flysystem configuration.', $serviceName));
121
			}
122
		}
123 1
	}
124
125
	/**
126
	 * @param string $type
127
	 * @param string $name
128
	 * @param string $class
129
	 * @param string $factory
130
	 * @param array $arguments
131
	 *
132
	 * @return void
133
	 */
134
	private function registerService(string $type, string $name, string $class, string $factory, array $arguments = []) : void
135
	{
136
		// Check if service class exists
137 1
		if (!class_exists($class)) {
138
			throw new Exceptions\InvalidArgumentException(sprintf('Class "%s" for service "%s" of "%s" does not exists.', $class, $name, $type));
139
		}
140
141
		/** @var DI\ContainerBuilder $builder */
142 1
		$builder = $this->getContainerBuilder();
143
144 1
		$builder->addDefinition($this->prefix($type . '.' . $name))
145 1
			->setType($class)
146 1
			->setFactory($factory)
147 1
			->setArguments($arguments)
148 1
			->addTag('ipub.flysystem.' . $type);
149 1
	}
150
151
	/**
152
	 * @param array|NULL $parameters
153
	 * @param array $configuration
154
	 * @param string $serviceName
155
	 *
156
	 * @return Utils\ArrayHash
157
	 *
158
	 * @throws Exceptions\InvalidParameterException
159
	 * @throws Exceptions\InvalidAdapterException
160
	 * @throws Utils\AssertionException
161
	 */
162
	private function validateParameters(?array $parameters, array $configuration, string $serviceName) : Utils\ArrayHash
163
	{
164 1
		$collection = [];
165
166 1
		if ($parameters === NULL) {
167 1
			return Utils\ArrayHash::from([]);
168
		}
169
170 1
		foreach ($parameters as $name => $definition) {
171 1
			if (!array_key_exists($name, $configuration) && $definition['required']) {
172
				throw new Exceptions\InvalidParameterException(sprintf('The parameter "%s" for "%s" is required.', $name, $serviceName));
173
			}
174
175 1
			if (array_key_exists('default', $definition)) {
176 1
				$collection[$name] = $definition['default'];
177
			}
178
179 1
			if (array_key_exists($name, $configuration)) {
180 1
				Utils\Validators::assert($configuration[$name], $definition['type'], $name);
181
182 1
				if (isset($definition['values']) && !in_array($configuration[$name], $definition['values'])) {
183
					throw new Exceptions\InvalidParameterException(sprintf('The parameter "%s" for "%s" is not in allowed range [%s].', $name, $serviceName, implode(', ', $definition['values'])));
184
				}
185
186 1
				$collection[$name] = $configuration[$name];
187
			}
188
		}
189
190 1
		$collection['extensionPrefix'] = $this->name;
191
192 1
		return Utils\ArrayHash::from($collection);
193
	}
194
195
	/**
196
	 * @param Nette\Configurator $config
197
	 * @param string $extensionName
198
	 *
199
	 * @return void
200
	 */
201
	public static function register(Nette\Configurator $config, string $extensionName = 'flysystem') : void
202
	{
203 1
		$config->onCompile[] = function (Nette\Configurator $config, Nette\DI\Compiler $compiler) use ($extensionName) {
204 1
			$compiler->addExtension($extensionName, new FlysystemExtension);
205 1
		};
206 1
	}
207
}
208