Completed
Push — master ( 2a17e7...e610ee )
by Arne
04:45
created

Container::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 64
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 64
rs 9.3956
c 0
b 0
f 0
cc 2
eloc 40
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Storeman;
4
5
use League\Container\Definition\DefinitionInterface;
6
use Psr\Container\ContainerInterface;
7
use Psr\Log\LoggerAwareInterface;
8
use Psr\Log\LoggerInterface;
9
use Psr\Log\NullLogger;
10
use Storeman\Config\Configuration;
11
use Storeman\ConflictHandler\ConflictHandlerInterface;
12
use Storeman\ConflictHandler\PanickingConflictHandler;
13
use Storeman\ConflictHandler\PreferLocalConflictHandler;
14
use Storeman\ConflictHandler\PreferRemoteConflictHandler;
15
use Storeman\Hash\Algorithm\Adler32;
16
use Storeman\Hash\Algorithm\Crc32;
17
use Storeman\Hash\Algorithm\HashAlgorithmInterface;
18
use Storeman\Hash\Algorithm\Md5;
19
use Storeman\Hash\Algorithm\Sha1;
20
use Storeman\Hash\Algorithm\Sha256;
21
use Storeman\Hash\Algorithm\Sha512;
22
use Storeman\Hash\HashProvider;
23
use Storeman\IndexBuilder\IndexBuilderInterface;
24
use Storeman\IndexBuilder\StandardIndexBuilder;
25
use Storeman\IndexMerger\IndexMergerInterface;
26
use Storeman\IndexMerger\StandardIndexMerger;
27
use Storeman\LockAdapter\DummyLockAdapter;
28
use Storeman\LockAdapter\LockAdapterInterface;
29
use Storeman\LockAdapter\StorageBasedLockAdapter;
30
use Storeman\OperationListBuilder\OperationListBuilderInterface;
31
use Storeman\OperationListBuilder\StandardOperationListBuilder;
32
use Storeman\StorageAdapter\LocalStorageAdapter;
33
use Storeman\StorageAdapter\StorageAdapterInterface;
34
use Storeman\Validation\Constraints\ExistingServiceValidator;
35
use Storeman\VaultLayout\Amberjack\AmberjackVaultLayout;
36
use Storeman\VaultLayout\VaultLayoutInterface;
37
38
/**
39
 * Dependency injection container for modularized parts.
40
 * It is basically a facade for a PSR container implementation with some additional accessors for type safety.
41
 */
42
final class Container implements ContainerInterface
43
{
44
    protected const PREFIX_CONFLICT_HANDLER = 'conflictHandler.';
45
    protected const PREFIX_HASH_ALGORITHM = 'hashAlgorithm.';
46
    protected const PREFIX_INDEX_BUILDER = 'indexBuilder.';
47
    protected const PREFIX_INDEX_MERGER = 'indexMerger.';
48
    protected const PREFIX_LOCK_ADAPTER = 'lockAdapter.';
49
    protected const PREFIX_OPERATION_LIST_BUILDER = 'operationListBuilder.';
50
    protected const PREFIX_STORAGE_ADAPTER = 'storageAdapter.';
51
    protected const PREFIX_VAULT_LAYOUT = 'vaultLayout.';
52
53
54
    /**
55
     * @var InspectableContainer
56
     */
57
    protected $delegate;
58
59
    /**
60
     * Sets up the container with all bundled services.
61
     *
62
     * Note: Be very careful with shared services as the container is used shared by all vaults of a storeman instance.
63
     */
64
    public function __construct()
65
    {
66
        $this->delegate = new InspectableContainer();
67
68
        $this->delegate->inflector(LoggerAwareInterface::class)->invokeMethod('setLogger', ['logger']);
69
70
        $this->delegate->add('logger', NullLogger::class);
71
        $this->delegate->add('vaults', VaultContainer::class, true)->withArguments(['configuration', 'storeman']);
72
        $this->delegate->add('vaultConfiguration', function(Vault $vault) { return $vault->getVaultConfiguration(); })->withArgument('vault');
73
74
        $this->addHashAlgorithm('adler32', Adler32::class);
75
        $this->addHashAlgorithm('crc32', Crc32::class);
76
        $this->addHashAlgorithm('md5', Md5::class);
77
        $this->addHashAlgorithm('sha1', Sha1::class);
78
        $this->addHashAlgorithm('sha256', Sha256::class);
79
        $this->addHashAlgorithm('sha512', Sha512::class);
80
81
        $this->delegate->add('hashFunctions', function(Container $container) {
82
83
            $return = [];
84
85
            foreach ($container->getHashAlgorithmNames() as $algorithm)
86
            {
87
                /** @var HashAlgorithmInterface $hashFunction */
88
                $hashFunction = $container->get($this->getHashAlgorithmServiceName($algorithm));
89
90
                assert($hashFunction instanceof HashAlgorithmInterface);
91
92
                $return[$hashFunction->getName()] = $hashFunction;
93
            }
94
95
            return $return;
96
97
        }, true)->withArgument($this);
98
99
        $this->delegate->add('fileReader', FileReader::class, true)->withArguments(['configuration', 'hashFunctions']);
100
        $this->delegate->add('hashProvider', HashProvider::class, true)->withArguments(['fileReader', 'configuration', 'hashFunctions']);
101
102
        $this->registerServiceFactory('indexBuilder');
103
        $this->addIndexBuilder('standard', StandardIndexBuilder::class, true);
104
105
        $this->registerVaultServiceFactory('conflictHandler');
106
        $this->addConflictHandler('panicking', PanickingConflictHandler::class, true);
107
        $this->addConflictHandler('preferLocal', PreferLocalConflictHandler::class, true);
108
        $this->addConflictHandler('preferRemote', PreferRemoteConflictHandler::class, true);
109
110
        $this->registerVaultServiceFactory('indexMerger');
111
        $this->addIndexMerger('standard', StandardIndexMerger::class, true)->withArguments(['configuration', 'hashProvider']);
112
113
        $this->registerVaultServiceFactory('lockAdapter');
114
        $this->addLockAdapter('dummy', DummyLockAdapter::class);
115
        $this->addLockAdapter('storage', StorageBasedLockAdapter::class)->withArguments(['storageAdapter']);
116
117
        $this->registerVaultServiceFactory('operationListBuilder');
118
        $this->addOperationListBuilder('standard', StandardOperationListBuilder::class, true);
119
120
        $this->registerVaultServiceFactory('storageAdapter', 'adapter');
121
        $this->addStorageAdapter('local', LocalStorageAdapter::class)->withArgument('vaultConfiguration');
122
123
        $this->registerVaultServiceFactory('vaultLayout');
124
        $this->addVaultLayout('amberjack', AmberjackVaultLayout::class)->withArguments(['storageAdapter', 'vaultConfiguration']);
125
126
        $this->delegate->add(ExistingServiceValidator::class)->withArgument($this);
127
    }
128
129
    public function injectConfiguration(Configuration $configuration): Container
130
    {
131
        if ($this->has('configuration'))
132
        {
133
            throw new \RuntimeException();
134
        }
135
136
        $this->delegate->add('configuration', $configuration, true);
137
138
        return $this;
139
    }
140
141
    public function injectStoreman(Storeman $storeman): Container
142
    {
143
        if ($this->has('storeman'))
144
        {
145
            throw new \RuntimeException();
146
        }
147
148
        $this->delegate->add('storeman', $storeman, true);
149
150
        return $this;
151
    }
152
153
    /**
154
     * Selects the given vault (or no vault) as the current one.
155
     *
156
     * @param Vault $vault
157
     * @return Container
158
     */
159
    public function selectVault(Vault $vault = null): Container
160
    {
161
        $this->delegate->add('vault', $vault, true);
162
163
        return $this;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function get($id)
170
    {
171
        return $this->delegate->get($id);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function has($id)
178
    {
179
        return $this->delegate->has($id);
180
    }
181
182
183
    public function getStoreman(): Storeman
184
    {
185
        return $this->get('storeman');
186
    }
187
188
    public function getConfiguration(): Configuration
189
    {
190
        return $this->get('configuration');
191
    }
192
193
    public function getVaultContainer(): VaultContainer
194
    {
195
        return $this->get('vaults');
196
    }
197
198
    public function getSelectedVault(): ?Vault
199
    {
200
        return $this->get('vault');
201
    }
202
203
204
    public function getLogger(): LoggerInterface
205
    {
206
        return $this->get('logger');
207
    }
208
209
    public function setLogger(LoggerInterface $logger): Container
210
    {
211
        $this->delegate->add('logger', $logger);
212
213
        return $this;
214
    }
215
216
217
    public function getConflictHandler(string $name): ConflictHandlerInterface
218
    {
219
        return $this->delegate->get($this->getConflictHandlerServiceName($name));
220
    }
221
222
    public function addConflictHandler(string $name, $concrete, bool $shared = false): DefinitionInterface
223
    {
224
        return $this->delegate->add($this->getConflictHandlerServiceName($name), $concrete, $shared);
225
    }
226
227
    public function getConflictHandlerNames(): array
228
    {
229
        return $this->getServiceNamesWithPrefix(static::PREFIX_CONFLICT_HANDLER);
230
    }
231
232
233
    public function getHashAlgorithm(string $name): HashAlgorithmInterface
234
    {
235
        return $this->delegate->get($this->getHashAlgorithmServiceName($name));
236
    }
237
238
    public function addHashAlgorithm(string $name, $concrete, bool $shared = false): DefinitionInterface
239
    {
240
        return $this->delegate->add($this->getHashAlgorithmServiceName($name), $concrete, $shared);
241
    }
242
243
    public function getHashAlgorithmNames(): array
244
    {
245
        return $this->getServiceNamesWithPrefix(static::PREFIX_HASH_ALGORITHM);
246
    }
247
248
249
    public function getIndexMerger(string $name): IndexMergerInterface
250
    {
251
        return $this->delegate->get($this->getIndexMergerServiceName($name));
252
    }
253
254
    public function addIndexMerger(string $name, $concrete, bool $shared = false): DefinitionInterface
255
    {
256
        return $this->delegate->add($this->getIndexMergerServiceName($name), $concrete, $shared);
257
    }
258
259
    public function getIndexMergerNames(): array
260
    {
261
        return $this->getServiceNamesWithPrefix(static::PREFIX_INDEX_MERGER);
262
    }
263
264
265
    public function getIndexBuilder(string $name): IndexBuilderInterface
266
    {
267
        return $this->delegate->get($this->getIndexBuilderServiceName($name));
268
    }
269
270
    public function addIndexBuilder(string $name, $concrete, bool $shared = false): DefinitionInterface
271
    {
272
        return $this->delegate->add($this->getIndexBuilderServiceName($name), $concrete, $shared);
273
    }
274
275
    public function getIndexBuilderNames(): array
276
    {
277
        return $this->getServiceNamesWithPrefix(static::PREFIX_INDEX_BUILDER);
278
    }
279
280
281
    public function getLockAdapter(string $name): LockAdapterInterface
282
    {
283
        return $this->delegate->get($this->getLockAdapterServiceName($name));
284
    }
285
286
    public function addLockAdapter(string $name, $concrete, bool $shared = false): DefinitionInterface
287
    {
288
        return $this->delegate->add($this->getLockAdapterServiceName($name), $concrete, $shared);
289
    }
290
291
    public function getLockAdapterNames(): array
292
    {
293
        return $this->getServiceNamesWithPrefix(static::PREFIX_LOCK_ADAPTER);
294
    }
295
296
    
297
    public function getOperationListBuilder(string $name): OperationListBuilderInterface
298
    {
299
        return $this->delegate->get($this->getOperationListBuilderServiceName($name));
300
    }
301
302
    public function addOperationListBuilder(string $name, $concrete, bool $shared = false): DefinitionInterface
303
    {
304
        return $this->delegate->add($this->getOperationListBuilderServiceName($name), $concrete, $shared);
305
    }
306
307
    public function getOperationListBuilderNames(): array
308
    {
309
        return $this->getServiceNamesWithPrefix(static::PREFIX_OPERATION_LIST_BUILDER);
310
    }
311
312
313
    public function getStorageAdapter(string $name): StorageAdapterInterface
314
    {
315
        return $this->delegate->get($this->getStorageAdapterServiceName($name));
316
    }
317
318
    public function addStorageAdapter(string $name, $concrete, bool $shared = false): DefinitionInterface
319
    {
320
        return $this->delegate->add($this->getStorageAdapterServiceName($name), $concrete, $shared);
321
    }
322
323
    public function getStorageAdapterNames(): array
324
    {
325
        return $this->getServiceNamesWithPrefix(static::PREFIX_STORAGE_ADAPTER);
326
    }
327
328
329
    public function getVaultLayout(string $name): VaultLayoutInterface
330
    {
331
        return $this->delegate->get($this->getVaultLayoutServiceName($name));
332
    }
333
334
    public function addVaultLayout(string $name, $concrete, bool $shared = false): DefinitionInterface
335
    {
336
        return $this->delegate->add($this->getVaultLayoutServiceName($name), $concrete, $shared);
337
    }
338
339
    public function getVaultLayoutNames(): array
340
    {
341
        return $this->getServiceNamesWithPrefix(static::PREFIX_VAULT_LAYOUT);
342
    }
343
344
345
    protected function getConflictHandlerServiceName(string $name): string
346
    {
347
        return static::PREFIX_CONFLICT_HANDLER . $name;
348
    }
349
350
    protected function getHashAlgorithmServiceName(string $name): string
351
    {
352
        return static::PREFIX_HASH_ALGORITHM . $name;
353
    }
354
355
    protected function getIndexBuilderServiceName(string $name): string
356
    {
357
        return static::PREFIX_INDEX_BUILDER . $name;
358
    }
359
360
    protected function getIndexMergerServiceName(string $name): string
361
    {
362
        return static::PREFIX_INDEX_MERGER . $name;
363
    }
364
365
    protected function getLockAdapterServiceName(string $name): string
366
    {
367
        return static::PREFIX_LOCK_ADAPTER . $name;
368
    }
369
370
    protected function getOperationListBuilderServiceName(string $name): string
371
    {
372
        return static::PREFIX_OPERATION_LIST_BUILDER . $name;
373
    }
374
375
    protected function getStorageAdapterServiceName(string $name): string
376
    {
377
        return static::PREFIX_STORAGE_ADAPTER . $name;
378
    }
379
380
    protected function getVaultLayoutServiceName(string $name): string
381
    {
382
        return static::PREFIX_VAULT_LAYOUT . $name;
383
    }
384
385
    /**
386
     * Registers a factory for a type of service.
387
     *
388
     * @param string $type
389
     * @param string $configurationKey
390
     */
391
    protected function registerServiceFactory(string $type, string $configurationKey = null): void
392
    {
393
        $this->delegate->add($type, function(Configuration $configuration) use ($configurationKey, $type) {
394
395
            $array = $configuration->getArrayCopy();
396
            $configurationKey = $configurationKey ?: $type;
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $configurationKey, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
397
398
            if (!array_key_exists($configurationKey, $array))
399
            {
400
                throw new \LogicException("Unknown config key: {$configuration}");
401
            }
402
403
            return $this->delegate->get("{$type}.{$array[$configurationKey]}");
404
405
        })->withArgument('configuration');
406
    }
407
408
    /**
409
     * Registers a factory for a type of vault-specific module.
410
     *
411
     * @param string $type
412
     * @param string $vaultConfigurationKey
413
     */
414
    protected function registerVaultServiceFactory(string $type, string $vaultConfigurationKey = null): void
415
    {
416
        $this->delegate->add($type, function(Vault $vault) use ($type, $vaultConfigurationKey) {
417
418
            $array = $vault->getVaultConfiguration()->getArrayCopy();
419
            $vaultConfigurationKey = $vaultConfigurationKey ?: $type;
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $vaultConfigurationKey, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
420
421
            if (!array_key_exists($vaultConfigurationKey, $array))
422
            {
423
                throw new \LogicException("Unknown vault config key: {$vaultConfigurationKey}");
424
            }
425
426
            return $this->delegate->get("{$type}.{$array[$vaultConfigurationKey]}");
427
428
        })->withArgument('vault');
429
    }
430
431
    /**
432
     * Builds and returns list of added service names starting with a given prefix.
433
     *
434
     * @param string $prefix
435
     * @return string[]
436
     */
437
    protected function getServiceNamesWithPrefix(string $prefix): array
438
    {
439
        return array_map(
440
441
            // remove prefix
442
            function(string $alias) use ($prefix) {
443
                return substr($alias, strlen($prefix));
444
            },
445
446
            array_filter(
447
448
                // search in all registered services
449
                $this->delegate->getProvidedServiceNames(),
450
451
                // only service names with given prefix
452
                function(string $alias) use ($prefix) {
453
                    return substr($alias, 0, strlen($prefix)) === $prefix;
454
                }
455
            )
456
        );
457
    }
458
}
459