Passed
Push — refactor/setup-gacela-2 ( 32146e )
by Chema
05:11
created

SetupGacela::getProjectNamespaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\Bootstrap;
6
7
use Closure;
8
use Gacela\Framework\Bootstrap\Setup\BuilderExecutor;
9
use Gacela\Framework\Bootstrap\Setup\Combiner;
10
use Gacela\Framework\Bootstrap\Setup\GacelaConfigExtender;
11
use Gacela\Framework\Bootstrap\Setup\Properties;
12
use Gacela\Framework\Bootstrap\Setup\PropertyChangeTracker;
13
use Gacela\Framework\Bootstrap\Setup\SetupCombinator;
14
use Gacela\Framework\Config\GacelaConfigBuilder\AppConfigBuilder;
15
use Gacela\Framework\Config\GacelaConfigBuilder\BindingsBuilder;
16
use Gacela\Framework\Config\GacelaConfigBuilder\SuffixTypesBuilder;
17
use Gacela\Framework\Event\Dispatcher\EventDispatcherInterface;
18
use Override;
19
use RuntimeException;
20
21
use function is_callable;
22
use function sprintf;
23
24
/**
25
 * @psalm-suppress ArgumentTypeCoercion,MixedArgumentTypeCoercion
26
 */
27
final class SetupGacela extends AbstractSetupGacela
28
{
29
    private readonly Properties $properties;
30
31
    private readonly PropertyChangeTracker $changeTracker;
32
33
    private readonly BuilderExecutor $builderExecutor;
34
35
    public function __construct()
36
    {
37
        $this->properties = new Properties();
1 ignored issue
show
Bug introduced by
The property properties is declared read-only in Gacela\Framework\Bootstrap\SetupGacela.
Loading history...
38
        $this->changeTracker = new PropertyChangeTracker();
1 ignored issue
show
Bug introduced by
The property changeTracker is declared read-only in Gacela\Framework\Bootstrap\SetupGacela.
Loading history...
39
        $this->builderExecutor = new BuilderExecutor($this->properties);
1 ignored issue
show
Bug introduced by
The property builderExecutor is declared read-only in Gacela\Framework\Bootstrap\SetupGacela.
Loading history...
40
    }
41
42
    /**
43
     * @codeCoverageIgnore
44
     */
45
    public static function fromFile(string $gacelaFilePath): self
46
    {
47
        if (!is_file($gacelaFilePath)) {
48
            throw new RuntimeException(sprintf("Invalid file path: '%s'", $gacelaFilePath));
49
        }
50
51
        /** @var callable(GacelaConfig):void|null $setupGacelaFileFn */
52
        $setupGacelaFileFn = include $gacelaFilePath;
53
        if (!is_callable($setupGacelaFileFn)) {
54
            return new self();
55
        }
56
57
        return self::fromCallable($setupGacelaFileFn);
58
    }
59
60
    /**
61
     * @param callable(GacelaConfig):void $setupGacelaFileFn
62
     */
63
    public static function fromCallable(callable $setupGacelaFileFn): self
64
    {
65
        $gacelaConfig = new GacelaConfig();
66
        $setupGacelaFileFn($gacelaConfig);
67
68
        return self::fromGacelaConfig($gacelaConfig);
69
    }
70
71
    public static function fromGacelaConfig(GacelaConfig $gacelaConfig): self
72
    {
73
        (new GacelaConfigExtender())->extend($gacelaConfig);
74
75
        $dto = $gacelaConfig->toTransfer();
76
77
        return (new self())
78
            ->setExternalServices($dto->externalServices)
79
            ->setAppConfigBuilder($dto->appConfigBuilder)
80
            ->setSuffixTypesBuilder($dto->suffixTypesBuilder)
81
            ->setBindingsBuilder($dto->bindingsBuilder)
82
            ->setShouldResetInMemoryCache($dto->shouldResetInMemoryCache)
83
            ->setFileCacheEnabled($dto->fileCacheEnabled)
84
            ->setFileCacheDirectory($dto->fileCacheDirectory)
85
            ->setProjectNamespaces($dto->projectNamespaces)
86
            ->setConfigKeyValues($dto->configKeyValues)
87
            ->setAreEventListenersEnabled($dto->areEventListenersEnabled)
88
            ->setGenericListeners($dto->genericListeners)
89
            ->setSpecificListeners($dto->specificListeners)
90
            ->setGacelaConfigsToExtend($dto->gacelaConfigsToExtend)
91
            ->setPlugins($dto->plugins)
92
            ->setServicesToExtend($dto->servicesToExtend);
93
    }
94
95
    /**
96
     * @param array<string,class-string|object|callable> $array
97
     */
98
    public function setExternalServices(?array $array): self
99
    {
100
        $this->markPropertyAsChanged(self::externalServices, $array !== null);
101
        $this->properties->externalServices = $array;
102
103
        return $this;
104
    }
105
106
    public function setAppConfigBuilder(AppConfigBuilder $builder): self
107
    {
108
        $this->properties->appConfigBuilder = $builder;
109
110
        return $this;
111
    }
112
113
    public function setSuffixTypesBuilder(SuffixTypesBuilder $builder): self
114
    {
115
        $this->properties->suffixTypesBuilder = $builder;
116
117
        return $this;
118
    }
119
120
    public function setBindingsBuilder(BindingsBuilder $builder): self
121
    {
122
        $this->properties->bindingsBuilder = $builder;
123
124
        return $this;
125
    }
126
127
    /**
128
     * @param callable(AppConfigBuilder):void $callable
129
     */
130
    public function setAppConfigFn(callable $callable): self
131
    {
132
        $this->properties->appConfigFn = $callable;
133
134
        return $this;
135
    }
136
137
    #[Override]
138
    public function buildAppConfig(AppConfigBuilder $builder): AppConfigBuilder
139
    {
140
        $builder = parent::buildAppConfig($builder);
141
142
        return $this->builderExecutor->buildAppConfig($builder);
143
    }
144
145
    /**
146
     * @param callable(BindingsBuilder,array<string,mixed>):void $callable
147
     */
148
    public function setBindingsFn(callable $callable): self
149
    {
150
        $this->properties->bindingsFn = $callable;
151
152
        return $this;
153
    }
154
155
    /**
156
     * Define the mapping between interfaces and concretions, so Gacela services will auto-resolve them automatically.
157
     *
158
     * @param array<string,class-string|object|callable> $externalServices
159
     */
160
    #[Override]
161
    public function buildBindings(
162
        BindingsBuilder $builder,
163
        array $externalServices,
164
    ): BindingsBuilder {
165
        $builder = parent::buildBindings($builder, $externalServices);
166
167
        return $this->builderExecutor->buildBindings($builder, $externalServices);
168
    }
169
170
    /**
171
     * @param callable(SuffixTypesBuilder):void $callable
172
     */
173
    public function setSuffixTypesFn(callable $callable): self
174
    {
175
        $this->properties->suffixTypesFn = $callable;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Allow overriding gacela resolvable types.
182
     */
183
    #[Override]
184
    public function buildSuffixTypes(SuffixTypesBuilder $builder): SuffixTypesBuilder
185
    {
186
        $builder = parent::buildSuffixTypes($builder);
187
188
        return $this->builderExecutor->buildSuffixTypes($builder);
189
    }
190
191
    /**
192
     * @return array<string, class-string|object|callable>
193
     */
194
    #[Override]
195
    public function externalServices(): array
196
    {
197
        return array_merge(
198
            parent::externalServices(),
199
            $this->properties->externalServices ?? [],
200
        );
201
    }
202
203
    public function setShouldResetInMemoryCache(?bool $flag): self
204
    {
205
        $this->markPropertyAsChanged(self::shouldResetInMemoryCache, $flag !== null);
206
        $this->properties->shouldResetInMemoryCache = $flag ?? self::DEFAULT_SHOULD_RESET_IN_MEMORY_CACHE;
207
208
        return $this;
209
    }
210
211
    #[Override]
212
    public function shouldResetInMemoryCache(): bool
213
    {
214
        return (bool)$this->properties->shouldResetInMemoryCache;
215
    }
216
217
    #[Override]
218
    public function isFileCacheEnabled(): bool
219
    {
220
        return (bool)$this->properties->fileCacheEnabled;
221
    }
222
223
    #[Override]
224
    public function getFileCacheDirectory(): string
225
    {
226
        return (string)$this->properties->fileCacheDirectory;
227
    }
228
229
    public function setFileCacheDirectory(?string $dir): self
230
    {
231
        $this->markPropertyAsChanged(self::fileCacheDirectory, $dir !== null);
232
        $this->properties->fileCacheDirectory = $dir ?? self::DEFAULT_FILE_CACHE_DIRECTORY;
233
234
        return $this;
235
    }
236
237
    /**
238
     * @param ?list<string> $list
239
     */
240
    public function setProjectNamespaces(?array $list): self
241
    {
242
        $this->markPropertyAsChanged(self::projectNamespaces, $list !== null);
243
        $this->properties->projectNamespaces = $list ?? self::DEFAULT_PROJECT_NAMESPACES;
0 ignored issues
show
Documentation Bug introduced by
It seems like $list ?? self::DEFAULT_PROJECT_NAMESPACES of type array is incompatible with the declared type Gacela\Framework\Bootstrap\Setup\list|null of property $projectNamespaces.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
244
245
        return $this;
246
    }
247
248
    /**
249
     * @return list<string>
250
     */
251
    #[Override]
252
    public function getProjectNamespaces(): array
253
    {
254
        return (array)$this->properties->projectNamespaces;
255
    }
256
257
    /**
258
     * @return array<string,mixed>
259
     */
260
    #[Override]
261
    public function getConfigKeyValues(): array
262
    {
263
        return (array)$this->properties->configKeyValues;
264
    }
265
266
    #[Override]
267
    public function getEventDispatcher(): EventDispatcherInterface
268
    {
269
        return $this->properties->eventDispatcher ??= SetupEventDispatcher::getDispatcher($this);
270
    }
271
272
    /**
273
     * @return array<string,list<Closure>>
274
     */
275
    #[Override]
276
    public function getServicesToExtend(): array
277
    {
278
        return (array)$this->properties->servicesToExtend;
279
    }
280
281
    public function setFileCacheEnabled(?bool $flag): self
282
    {
283
        $this->markPropertyAsChanged(self::fileCacheEnabled, $flag !== null);
284
        $this->properties->fileCacheEnabled = $flag ?? self::DEFAULT_FILE_CACHE_ENABLED;
285
286
        return $this;
287
    }
288
289
    public function canCreateEventDispatcher(): bool
290
    {
291
        return $this->properties->areEventListenersEnabled === true
292
            && $this->hasEventListeners();
293
    }
294
295
    /**
296
     * @param ?array<string,mixed> $configKeyValues
297
     */
298
    public function setConfigKeyValues(?array $configKeyValues): self
299
    {
300
        $this->markPropertyAsChanged(self::configKeyValues, $configKeyValues !== null);
301
        $this->properties->configKeyValues = $configKeyValues ?? self::DEFAULT_CONFIG_KEY_VALUES;
302
303
        return $this;
304
    }
305
306
    /**
307
     * @return array<class-string,list<callable>>|null
308
     */
309
    public function getSpecificListeners(): ?array
310
    {
311
        return $this->properties->specificListeners;
312
    }
313
314
    /**
315
     * @return list<callable>|null
316
     */
317
    public function getGenericListeners(): ?array
318
    {
319
        return $this->properties->genericListeners;
320
    }
321
322
    public function isPropertyChanged(string $name): bool
323
    {
324
        return $this->changeTracker->isChanged($name);
325
    }
326
327
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): self
328
    {
329
        $this->properties->eventDispatcher = $eventDispatcher;
330
331
        return $this;
332
    }
333
334
    #[Override]
335
    public function combine(self $other): self
336
    {
337
        return (new SetupCombinator($this))->combine($other);
338
    }
339
340
    /**
341
     * @param list<Closure> $servicesToExtend
342
     */
343
    public function addServicesToExtend(string $serviceId, array $servicesToExtend): self
344
    {
345
        $this->properties->servicesToExtend[$serviceId] ??= [];
346
        $this->properties->servicesToExtend[$serviceId] = [...$this->properties->servicesToExtend[$serviceId], ...$servicesToExtend];
347
348
        return $this;
349
    }
350
351
    /**
352
     * @param array<string,class-string|object|callable> $list
353
     */
354
    public function combineExternalServices(array $list): void
355
    {
356
        (new Combiner($this))->combineExternalServices($list);
357
    }
358
359
    /**
360
     * @param list<string> $list
361
     */
362
    public function combineProjectNamespaces(array $list): void
363
    {
364
        (new Combiner($this))->combineProjectNamespaces($list);
365
    }
366
367
    /**
368
     * @param array<string,mixed> $list
369
     */
370
    public function combineConfigKeyValues(array $list): void
371
    {
372
        (new Combiner($this))->combineConfigKeyValues($list);
373
    }
374
375
    /**
376
     * @param list<class-string> $list
377
     */
378
    public function combineGacelaConfigsToExtend(array $list): void
379
    {
380
        (new Combiner($this))->combineGacelaConfigsToExtend($list);
381
    }
382
383
    /**
384
     * @param list<class-string|callable> $list
385
     */
386
    public function combinePlugins(array $list): void
387
    {
388
        (new Combiner($this))->combinePlugins($list);
389
    }
390
391
    /**
392
     * @return list<class-string>
393
     */
394
    #[Override]
395
    public function getGacelaConfigsToExtend(): array
396
    {
397
        return (array)$this->properties->gacelaConfigsToExtend;
398
    }
399
400
    /**
401
     * @return list<class-string|callable>
402
     */
403
    #[Override]
404
    public function getPlugins(): array
405
    {
406
        return (array)$this->properties->plugins;
407
    }
408
409
    private function setAreEventListenersEnabled(?bool $flag): self
410
    {
411
        $this->properties->areEventListenersEnabled = $flag ?? self::DEFAULT_ARE_EVENT_LISTENERS_ENABLED;
412
413
        return $this;
414
    }
415
416
    private function hasEventListeners(): bool
417
    {
418
        return ($this->properties->genericListeners !== null && $this->properties->genericListeners !== [])
419
            || ($this->properties->specificListeners !== null && $this->properties->specificListeners !== []);
420
    }
421
422
    /**
423
     * @param ?list<callable> $listeners
424
     */
425
    private function setGenericListeners(?array $listeners): self
426
    {
427
        $this->properties->genericListeners = $listeners ?? self::DEFAULT_GENERIC_LISTENERS;
0 ignored issues
show
Documentation Bug introduced by
It seems like $listeners ?? self::DEFAULT_GENERIC_LISTENERS of type array is incompatible with the declared type Gacela\Framework\Bootstrap\Setup\list|null of property $genericListeners.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
428
429
        return $this;
430
    }
431
432
    /**
433
     * @param ?array<string,list<Closure>> $list
434
     */
435
    private function setServicesToExtend(?array $list): self
436
    {
437
        $this->markPropertyAsChanged(self::servicesToExtend, $list !== null);
438
        $this->properties->servicesToExtend = $list ?? self::DEFAULT_SERVICES_TO_EXTEND;
439
440
        return $this;
441
    }
442
443
    /**
444
     * @param ?list<class-string> $list
445
     */
446
    private function setGacelaConfigsToExtend(?array $list): self
447
    {
448
        $this->markPropertyAsChanged(self::gacelaConfigsToExtend, $list !== null);
449
        $this->properties->gacelaConfigsToExtend = $list ?? self::DEFAULT_GACELA_CONFIGS_TO_EXTEND;
0 ignored issues
show
Documentation Bug introduced by
It seems like $list ?? self::DEFAULT_GACELA_CONFIGS_TO_EXTEND of type array is incompatible with the declared type Gacela\Framework\Bootstrap\Setup\list|null of property $gacelaConfigsToExtend.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
450
451
        return $this;
452
    }
453
454
    /**
455
     * @param ?list<class-string|callable> $list
456
     */
457
    private function setPlugins(?array $list): self
458
    {
459
        $this->markPropertyAsChanged(self::plugins, $list !== null);
460
        $this->properties->plugins = $list ?? self::DEFAULT_PLUGINS;
0 ignored issues
show
Documentation Bug introduced by
It seems like $list ?? self::DEFAULT_PLUGINS of type array is incompatible with the declared type Gacela\Framework\Bootstrap\Setup\list|null of property $plugins.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
461
462
        return $this;
463
    }
464
465
    /**
466
     * @param ?array<class-string,list<callable>> $listeners
467
     */
468
    private function setSpecificListeners(?array $listeners): self
469
    {
470
        $this->properties->specificListeners = $listeners ?? self::DEFAULT_SPECIFIC_LISTENERS;
471
472
        return $this;
473
    }
474
475
    private function markPropertyAsChanged(string $name, bool $isChanged): void
476
    {
477
        if ($isChanged) {
478
            $this->changeTracker->markAsChanged($name);
479
        } else {
480
            $this->changeTracker->markAsUnchanged($name);
481
        }
482
    }
483
}
484