Container::getIndexMergerNames()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\Config\ConfigurationFileReader;
12
use Storeman\ConflictHandler\ConflictHandlerInterface;
13
use Storeman\ConflictHandler\PanickingConflictHandler;
14
use Storeman\ConflictHandler\PreferLocalConflictHandler;
15
use Storeman\ConflictHandler\PreferRemoteConflictHandler;
16
use Storeman\Hash\Algorithm\Adler32;
17
use Storeman\Hash\Algorithm\Crc32;
18
use Storeman\Hash\Algorithm\HashAlgorithmInterface;
19
use Storeman\Hash\Algorithm\Md5;
20
use Storeman\Hash\Algorithm\Sha1;
21
use Storeman\Hash\Algorithm\Sha2_256;
22
use Storeman\Hash\Algorithm\Sha2_512;
23
use Storeman\Hash\HashProvider;
24
use Storeman\IndexBuilder\IndexBuilderInterface;
25
use Storeman\IndexBuilder\StandardIndexBuilder;
26
use Storeman\IndexMerger\IndexMergerInterface;
27
use Storeman\IndexMerger\StandardIndexMerger;
28
use Storeman\LockAdapter\DummyLockAdapter;
29
use Storeman\LockAdapter\LockAdapterInterface;
30
use Storeman\LockAdapter\StorageBasedLockAdapter;
31
use Storeman\OperationListBuilder\OperationListBuilderInterface;
32
use Storeman\OperationListBuilder\StandardOperationListBuilder;
33
use Storeman\StorageAdapter\Ftp;
34
use Storeman\StorageAdapter\Local;
35
use Storeman\StorageAdapter\S3;
36
use Storeman\StorageAdapter\StorageAdapterInterface;
37
use Storeman\Validation\Constraints\ExistingServiceValidator;
38
use Storeman\VaultLayout\Amberjack\AmberjackVaultLayout;
39
use Storeman\VaultLayout\VaultLayoutInterface;
40
41
/**
42
 * Dependency injection container for modularized parts.
43
 * It is basically a facade for a PSR container implementation with some additional accessors for type safety.
44
 */
45
final class Container implements ContainerInterface
46
{
47
    protected const PREFIX_CONFLICT_HANDLER = 'conflictHandler.';
48
    protected const PREFIX_HASH_ALGORITHM = 'hashAlgorithm.';
49
    protected const PREFIX_INDEX_BUILDER = 'indexBuilder.';
50
    protected const PREFIX_INDEX_MERGER = 'indexMerger.';
51
    protected const PREFIX_LOCK_ADAPTER = 'lockAdapter.';
52
    protected const PREFIX_OPERATION_LIST_BUILDER = 'operationListBuilder.';
53
    protected const PREFIX_STORAGE_ADAPTER = 'storageAdapter.';
54
    protected const PREFIX_VAULT_LAYOUT = 'vaultLayout.';
55
56
57
    /**
58
     * @var InspectableContainer
59
     */
60
    protected $delegate;
61
62
    /**
63
     * Sets up the container with all bundled services.
64
     *
65
     * Note: Be very careful with shared services as the container is used shared by all vaults of a storeman instance.
66
     */
67
    public function __construct()
68
    {
69
        $this->delegate = new InspectableContainer();
70
71
        $this->delegate->inflector(LoggerAwareInterface::class)->invokeMethod('setLogger', ['logger']);
72
73
        $this->delegate->add('logger', NullLogger::class);
74
        $this->delegate->add('vaults', VaultContainer::class, true)->withArguments(['configuration', 'storeman', 'logger']);
75
        $this->delegate->add('vaultConfiguration', function(Vault $vault) { return $vault->getVaultConfiguration(); })->withArgument('vault');
76
77
        $this->delegate->add('configurationFileReader', ConfigurationFileReader::class, true)->withArguments([$this]);
78
79
        $this->addHashAlgorithm('adler32', Adler32::class);
80
        $this->addHashAlgorithm('crc32', Crc32::class);
81
        $this->addHashAlgorithm('md5', Md5::class);
82
        $this->addHashAlgorithm('sha1', Sha1::class);
83
        $this->addHashAlgorithm('sha2-256', Sha2_256::class);
84
        $this->addHashAlgorithm('sha2-512', Sha2_512::class);
85
86
        $this->delegate->add('hashFunctions', function(Container $container) {
87
88
            $return = [];
89
90
            foreach ($container->getHashAlgorithmNames() as $algorithm)
91
            {
92
                /** @var HashAlgorithmInterface $hashFunction */
93
                $hashFunction = $container->get($this->getHashAlgorithmServiceName($algorithm));
94
95
                assert($hashFunction instanceof HashAlgorithmInterface);
96
97
                $return[$hashFunction->getName()] = $hashFunction;
98
            }
99
100
            return $return;
101
102
        }, true)->withArgument($this);
103
104
        $this->delegate->add('fileReader', FileReader::class, true)->withArguments(['configuration', 'hashFunctions']);
105
        $this->delegate->add('hashProvider', HashProvider::class, true)->withArguments(['fileReader', 'configuration', 'hashFunctions']);
106
107
        $this->registerServiceFactory('indexBuilder');
108
        $this->addIndexBuilder('standard', StandardIndexBuilder::class, true);
109
110
        $this->registerVaultServiceFactory('conflictHandler');
111
        $this->addConflictHandler('panicking', PanickingConflictHandler::class, true);
112
        $this->addConflictHandler('preferLocal', PreferLocalConflictHandler::class, true);
113
        $this->addConflictHandler('preferRemote', PreferRemoteConflictHandler::class, true);
114
115
        $this->registerVaultServiceFactory('indexMerger');
116
        $this->addIndexMerger('standard', StandardIndexMerger::class, true)->withArguments(['configuration', 'hashProvider']);
117
118
        $this->registerVaultServiceFactory('lockAdapter');
119
        $this->addLockAdapter('dummy', DummyLockAdapter::class)->withArguments(['configuration']);
120
        $this->addLockAdapter('storage', StorageBasedLockAdapter::class)->withArguments(['configuration', 'storageAdapter']);
121
122
        $this->registerVaultServiceFactory('operationListBuilder');
123
        $this->addOperationListBuilder('standard', StandardOperationListBuilder::class, true);
124
125
        $this->registerVaultServiceFactory('storageAdapter', 'adapter');
126
        $this->addStorageAdapter('ftp', Ftp::class)->withArgument('vaultConfiguration');
127
        $this->addStorageAdapter('local', Local::class)->withArgument('vaultConfiguration');
128
        $this->addStorageAdapter('s3', S3::class)->withArgument('vaultConfiguration');
129
130
        $this->registerVaultServiceFactory('vaultLayout');
131
        $this->addVaultLayout('amberjack', AmberjackVaultLayout::class)->withArguments(['storageAdapter']);
132
133
        $this->delegate->add(ExistingServiceValidator::class)->withArgument($this);
134
    }
135
136
    public function injectConfiguration(Configuration $configuration): Container
137
    {
138
        if ($this->has('configuration'))
139
        {
140
            throw new \RuntimeException();
141
        }
142
143
        $this->delegate->add('configuration', $configuration, true);
144
145
        return $this;
146
    }
147
148
    public function injectStoreman(Storeman $storeman): Container
149
    {
150
        if ($this->has('storeman'))
151
        {
152
            throw new \RuntimeException();
153
        }
154
155
        $this->delegate->add('storeman', $storeman, true);
156
157
        return $this;
158
    }
159
160
    /**
161
     * Selects the given vault (or no vault) as the current one.
162
     *
163
     * @param Vault $vault
164
     * @return Container
165
     */
166
    public function selectVault(Vault $vault = null): Container
167
    {
168
        $this->delegate->add('vault', $vault, true);
169
170
        return $this;
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function get($id)
177
    {
178
        return $this->delegate->get($id);
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function has($id)
185
    {
186
        return $this->delegate->has($id);
187
    }
188
189
190
    public function getStoreman(): Storeman
191
    {
192
        return $this->get('storeman');
193
    }
194
195
    public function getConfiguration(): Configuration
196
    {
197
        return $this->get('configuration');
198
    }
199
200
    public function getVaultContainer(): VaultContainer
201
    {
202
        return $this->get('vaults');
203
    }
204
205
    public function getSelectedVault(): ?Vault
206
    {
207
        return $this->get('vault');
208
    }
209
210
211
    public function getLogger(): LoggerInterface
212
    {
213
        return $this->get('logger');
214
    }
215
216
    public function setLogger(LoggerInterface $logger): Container
217
    {
218
        $this->delegate->add('logger', $logger);
219
220
        return $this;
221
    }
222
223
224
    public function getConflictHandler(string $name): ConflictHandlerInterface
225
    {
226
        return $this->delegate->get($this->getConflictHandlerServiceName($name));
227
    }
228
229
    public function addConflictHandler(string $name, $concrete, bool $shared = false): DefinitionInterface
230
    {
231
        return $this->delegate->add($this->getConflictHandlerServiceName($name), $concrete, $shared);
232
    }
233
234
    public function getConflictHandlerNames(): array
235
    {
236
        return $this->getServiceNamesWithPrefix(static::PREFIX_CONFLICT_HANDLER);
237
    }
238
239
240
    public function getHashAlgorithm(string $name): HashAlgorithmInterface
241
    {
242
        return $this->delegate->get($this->getHashAlgorithmServiceName($name));
243
    }
244
245
    public function addHashAlgorithm(string $name, $concrete, bool $shared = false): DefinitionInterface
246
    {
247
        return $this->delegate->add($this->getHashAlgorithmServiceName($name), $concrete, $shared);
248
    }
249
250
    public function getHashAlgorithmNames(): array
251
    {
252
        return $this->getServiceNamesWithPrefix(static::PREFIX_HASH_ALGORITHM);
253
    }
254
255
256
    public function getIndexMerger(string $name): IndexMergerInterface
257
    {
258
        return $this->delegate->get($this->getIndexMergerServiceName($name));
259
    }
260
261
    public function addIndexMerger(string $name, $concrete, bool $shared = false): DefinitionInterface
262
    {
263
        return $this->delegate->add($this->getIndexMergerServiceName($name), $concrete, $shared);
264
    }
265
266
    public function getIndexMergerNames(): array
267
    {
268
        return $this->getServiceNamesWithPrefix(static::PREFIX_INDEX_MERGER);
269
    }
270
271
272
    public function getIndexBuilder(string $name): IndexBuilderInterface
273
    {
274
        return $this->delegate->get($this->getIndexBuilderServiceName($name));
275
    }
276
277
    public function addIndexBuilder(string $name, $concrete, bool $shared = false): DefinitionInterface
278
    {
279
        return $this->delegate->add($this->getIndexBuilderServiceName($name), $concrete, $shared);
280
    }
281
282
    public function getIndexBuilderNames(): array
283
    {
284
        return $this->getServiceNamesWithPrefix(static::PREFIX_INDEX_BUILDER);
285
    }
286
287
288
    public function getLockAdapter(string $name): LockAdapterInterface
289
    {
290
        return $this->delegate->get($this->getLockAdapterServiceName($name));
291
    }
292
293
    public function addLockAdapter(string $name, $concrete, bool $shared = false): DefinitionInterface
294
    {
295
        return $this->delegate->add($this->getLockAdapterServiceName($name), $concrete, $shared);
296
    }
297
298
    public function getLockAdapterNames(): array
299
    {
300
        return $this->getServiceNamesWithPrefix(static::PREFIX_LOCK_ADAPTER);
301
    }
302
303
    
304
    public function getOperationListBuilder(string $name): OperationListBuilderInterface
305
    {
306
        return $this->delegate->get($this->getOperationListBuilderServiceName($name));
307
    }
308
309
    public function addOperationListBuilder(string $name, $concrete, bool $shared = false): DefinitionInterface
310
    {
311
        return $this->delegate->add($this->getOperationListBuilderServiceName($name), $concrete, $shared);
312
    }
313
314
    public function getOperationListBuilderNames(): array
315
    {
316
        return $this->getServiceNamesWithPrefix(static::PREFIX_OPERATION_LIST_BUILDER);
317
    }
318
319
320
    public function getStorageAdapter(string $name): StorageAdapterInterface
321
    {
322
        return $this->delegate->get($this->getStorageAdapterServiceName($name));
323
    }
324
325
    public function addStorageAdapter(string $name, $concrete, bool $shared = false): DefinitionInterface
326
    {
327
        return $this->delegate->add($this->getStorageAdapterServiceName($name), $concrete, $shared);
328
    }
329
330
    public function getStorageAdapterNames(): array
331
    {
332
        return $this->getServiceNamesWithPrefix(static::PREFIX_STORAGE_ADAPTER);
333
    }
334
335
336
    public function getVaultLayout(string $name): VaultLayoutInterface
337
    {
338
        return $this->delegate->get($this->getVaultLayoutServiceName($name));
339
    }
340
341
    public function addVaultLayout(string $name, $concrete, bool $shared = false): DefinitionInterface
342
    {
343
        return $this->delegate->add($this->getVaultLayoutServiceName($name), $concrete, $shared);
344
    }
345
346
    public function getVaultLayoutNames(): array
347
    {
348
        return $this->getServiceNamesWithPrefix(static::PREFIX_VAULT_LAYOUT);
349
    }
350
351
352
    protected function getConflictHandlerServiceName(string $name): string
353
    {
354
        return static::PREFIX_CONFLICT_HANDLER . $name;
355
    }
356
357
    protected function getHashAlgorithmServiceName(string $name): string
358
    {
359
        return static::PREFIX_HASH_ALGORITHM . $name;
360
    }
361
362
    protected function getIndexBuilderServiceName(string $name): string
363
    {
364
        return static::PREFIX_INDEX_BUILDER . $name;
365
    }
366
367
    protected function getIndexMergerServiceName(string $name): string
368
    {
369
        return static::PREFIX_INDEX_MERGER . $name;
370
    }
371
372
    protected function getLockAdapterServiceName(string $name): string
373
    {
374
        return static::PREFIX_LOCK_ADAPTER . $name;
375
    }
376
377
    protected function getOperationListBuilderServiceName(string $name): string
378
    {
379
        return static::PREFIX_OPERATION_LIST_BUILDER . $name;
380
    }
381
382
    protected function getStorageAdapterServiceName(string $name): string
383
    {
384
        return static::PREFIX_STORAGE_ADAPTER . $name;
385
    }
386
387
    protected function getVaultLayoutServiceName(string $name): string
388
    {
389
        return static::PREFIX_VAULT_LAYOUT . $name;
390
    }
391
392
    /**
393
     * Registers a factory for a type of service.
394
     *
395
     * @param string $type
396
     * @param string $configurationKey
397
     */
398
    protected function registerServiceFactory(string $type, string $configurationKey = null): void
399
    {
400
        $this->delegate->add($type, function(Configuration $configuration) use ($configurationKey, $type) {
401
402
            $array = $configuration->getArrayCopy();
403
            $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...
404
405
            if (!array_key_exists($configurationKey, $array))
406
            {
407
                throw new \LogicException("Unknown config key: {$configuration}");
408
            }
409
410
            return $this->delegate->get("{$type}.{$array[$configurationKey]}");
411
412
        })->withArgument('configuration');
413
    }
414
415
    /**
416
     * Registers a factory for a type of vault-specific module.
417
     *
418
     * @param string $type
419
     * @param string $vaultConfigurationKey
420
     */
421
    protected function registerVaultServiceFactory(string $type, string $vaultConfigurationKey = null): void
422
    {
423
        $this->delegate->add($type, function(Vault $vault) use ($type, $vaultConfigurationKey) {
424
425
            $array = $vault->getVaultConfiguration()->getArrayCopy();
426
            $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...
427
428
            if (!array_key_exists($vaultConfigurationKey, $array))
429
            {
430
                throw new \LogicException("Unknown vault config key: {$vaultConfigurationKey}");
431
            }
432
433
            return $this->delegate->get("{$type}.{$array[$vaultConfigurationKey]}");
434
435
        })->withArgument('vault');
436
    }
437
438
    /**
439
     * Builds and returns list of added service names starting with a given prefix.
440
     *
441
     * @param string $prefix
442
     * @return string[]
443
     */
444
    protected function getServiceNamesWithPrefix(string $prefix): array
445
    {
446
        return array_map(
447
448
            // remove prefix
449
            function(string $alias) use ($prefix) {
450
                return substr($alias, strlen($prefix));
451
            },
452
453
            array_filter(
454
455
                // search in all registered services
456
                $this->delegate->getProvidedServiceNames(),
457
458
                // only service names with given prefix
459
                function(string $alias) use ($prefix) {
460
                    return substr($alias, 0, strlen($prefix)) === $prefix;
461
                }
462
            )
463
        );
464
    }
465
}
466