Completed
Push — master ( 65b5b4...2290e5 )
by Arne
05:25
created

Container::setLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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