Passed
Push — feat/test-bash-tools ( d80278...b02152 )
by Chema
15:16 queued 11:00
created

SetupGacela::getProjectNamespaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\Bootstrap;
6
7
use Closure;
8
use Gacela\Framework\Bootstrap\Setup\GacelaConfigExtender;
9
use Gacela\Framework\Config\GacelaConfigBuilder\AppConfigBuilder;
10
use Gacela\Framework\Config\GacelaConfigBuilder\BindingsBuilder;
11
use Gacela\Framework\Config\GacelaConfigBuilder\SuffixTypesBuilder;
12
use Gacela\Framework\Event\Dispatcher\EventDispatcherInterface;
13
use RuntimeException;
14
15
use function array_unique;
16
use function is_callable;
17
18
/**
19
 * @psalm-suppress ArgumentTypeCoercion,MixedArgumentTypeCoercion
20
 */
21
final class SetupGacela extends AbstractSetupGacela
22
{
23
    /** @var callable(AppConfigBuilder):void */
24
    private $appConfigFn;
25
26
    /** @var callable(BindingsBuilder,array<string,mixed>):void */
27
    private $bindingsFn;
28
29
    /** @var callable(SuffixTypesBuilder):void */
30
    private $suffixTypesFn;
31
32
    /** @var ?array<string,class-string|object|callable> */
33
    private ?array $externalServices = null;
34
35
    private ?AppConfigBuilder $appConfigBuilder = null;
36
37
    private ?SuffixTypesBuilder $suffixTypesBuilder = null;
38
39
    private ?BindingsBuilder $bindingsBuilder = null;
40
41
    private ?bool $shouldResetInMemoryCache = null;
42
43
    private ?bool $fileCacheEnabled = null;
44
45
    private ?string $fileCacheDirectory = null;
46
47
    /** @var ?list<string> */
48
    private ?array $projectNamespaces = null;
49
50
    /** @var ?array<string,mixed> */
51
    private ?array $configKeyValues = null;
52
53
    private ?bool $areEventListenersEnabled = null;
54
55
    /** @var ?list<callable> */
56
    private ?array $genericListeners = null;
57
58
    /** @var ?array<class-string,list<callable>> */
59
    private ?array $specificListeners = null;
60
61
    private ?EventDispatcherInterface $eventDispatcher = null;
62
63
    /** @var ?array<string,bool> */
64
    private ?array $changedProperties = null;
65
66
    /** @var ?array<string,list<Closure>> */
67
    private ?array $servicesToExtend = null;
68
69
    /** @var ?list<class-string> */
70
    private ?array $gacelaConfigsToExtend = null;
71
72
    /** @var ?list<class-string|callable> */
73
    private ?array $plugins = null;
74
75 133
    public function __construct()
76
    {
77 133
        $emptyFn = static function (): void {
78 74
        };
79
80 133
        $this->appConfigFn = $emptyFn;
81 133
        $this->bindingsFn = $emptyFn;
82 133
        $this->suffixTypesFn = $emptyFn;
83
    }
84
85
    /**
86
     * @codeCoverageIgnore
87
     */
88
    public static function fromFile(string $gacelaFilePath): self
89
    {
90
        if (!is_file($gacelaFilePath)) {
91
            throw new RuntimeException(sprintf("Invalid file path: '%s'", $gacelaFilePath));
92
        }
93
94
        /** @var callable(GacelaConfig):void|null $setupGacelaFileFn */
95
        $setupGacelaFileFn = include $gacelaFilePath;
96
        if (!is_callable($setupGacelaFileFn)) {
97
            return new self();
98
        }
99
100
        return self::fromCallable($setupGacelaFileFn);
101
    }
102
103
    /**
104
     * @param callable(GacelaConfig):void $setupGacelaFileFn
105
     */
106 74
    public static function fromCallable(callable $setupGacelaFileFn): self
107
    {
108 74
        $gacelaConfig = new GacelaConfig();
109 74
        $setupGacelaFileFn($gacelaConfig);
110
111 74
        return self::fromGacelaConfig($gacelaConfig);
112
    }
113
114 93
    public static function fromGacelaConfig(GacelaConfig $gacelaConfig): self
115
    {
116 93
        (new GacelaConfigExtender())->extend($gacelaConfig);
117
118 93
        $dto = $gacelaConfig->toTransfer();
119
120 93
        return (new self())
121 93
            ->setExternalServices($dto->getExternalServices())
122 93
            ->setAppConfigBuilder($dto->getAppConfigBuilder())
123 93
            ->setSuffixTypesBuilder($dto->getSuffixTypesBuilder())
124 93
            ->setBindingsBuilder($dto->getBindingsBuilder())
125 93
            ->setShouldResetInMemoryCache($dto->getShouldResetInMemoryCache())
126 93
            ->setFileCacheEnabled($dto->getFileCacheEnabled())
127 93
            ->setFileCacheDirectory($dto->getFileCacheDirectory())
128 93
            ->setProjectNamespaces($dto->getProjectNamespaces())
129 93
            ->setConfigKeyValues($dto->getConfigKeyValues())
130 93
            ->setAreEventListenersEnabled($dto->getAreEventListenersEnabled())
131 93
            ->setGenericListeners($dto->getGenericListeners())
132 93
            ->setSpecificListeners($dto->getSpecificListeners())
133 93
            ->setGacelaConfigsToExtend($dto->getGacelaConfigsToExtend())
134 93
            ->setPlugins($dto->getPlugins())
135 93
            ->setServicesToExtend($dto->getServicesToExtend());
136
    }
137
138
    /**
139
     * @param array<string,class-string|object|callable> $array
140
     */
141 96
    public function setExternalServices(?array $array): self
142
    {
143 96
        $this->markPropertyChanged(self::externalServices, true);
144 96
        $this->externalServices = $array;
145
146 96
        return $this;
147
    }
148
149 93
    public function setAppConfigBuilder(AppConfigBuilder $builder): self
150
    {
151 93
        $this->appConfigBuilder = $builder;
152
153 93
        return $this;
154
    }
155
156 93
    public function setSuffixTypesBuilder(SuffixTypesBuilder $builder): self
157
    {
158 93
        $this->suffixTypesBuilder = $builder;
159
160 93
        return $this;
161
    }
162
163 93
    public function setBindingsBuilder(BindingsBuilder $builder): self
164
    {
165 93
        $this->bindingsBuilder = $builder;
166
167 93
        return $this;
168
    }
169
170
    /**
171
     * @param callable(AppConfigBuilder):void $callable
172
     */
173 3
    public function setAppConfigFn(callable $callable): self
174
    {
175 3
        $this->appConfigFn = $callable;
176
177 3
        return $this;
178
    }
179
180 75
    public function buildAppConfig(AppConfigBuilder $builder): AppConfigBuilder
181
    {
182 75
        $builder = parent::buildAppConfig($builder);
183
184 75
        if ($this->appConfigBuilder instanceof AppConfigBuilder) {
185 66
            $builder = $this->appConfigBuilder;
186
        }
187
188 75
        ($this->appConfigFn)($builder);
189
190 75
        return $builder;
191
    }
192
193
    /**
194
     * @param callable(BindingsBuilder,array<string,mixed>):void $callable
195
     */
196 3
    public function setBindingsFn(callable $callable): self
197
    {
198 3
        $this->bindingsFn = $callable;
199
200 3
        return $this;
201
    }
202
203
    /**
204
     * Define the mapping between interfaces and concretions, so Gacela services will auto-resolve them automatically.
205
     *
206
     * @param array<string,class-string|object|callable> $externalServices
207
     */
208 75
    public function buildBindings(
209
        BindingsBuilder $builder,
210
        array $externalServices,
211
    ): BindingsBuilder {
212 75
        $builder = parent::buildBindings($builder, $externalServices);
213
214 75
        if ($this->bindingsBuilder instanceof BindingsBuilder) {
215 66
            $builder = $this->bindingsBuilder;
216
        }
217
218 75
        ($this->bindingsFn)(
219 75
            $builder,
220 75
            array_merge($this->externalServices ?? [], $externalServices)
221 75
        );
222
223 75
        return $builder;
224
    }
225
226
    /**
227
     * @param callable(SuffixTypesBuilder):void $callable
228
     */
229 3
    public function setSuffixTypesFn(callable $callable): self
230
    {
231 3
        $this->suffixTypesFn = $callable;
232
233 3
        return $this;
234
    }
235
236
    /**
237
     * Allow overriding gacela resolvable types.
238
     */
239 75
    public function buildSuffixTypes(SuffixTypesBuilder $builder): SuffixTypesBuilder
240
    {
241 75
        $builder = parent::buildSuffixTypes($builder);
242
243 75
        if ($this->suffixTypesBuilder instanceof SuffixTypesBuilder) {
244 66
            $builder = $this->suffixTypesBuilder;
245
        }
246
247 75
        ($this->suffixTypesFn)($builder);
248
249 75
        return $builder;
250
    }
251
252
    /**
253
     * @return array<string, class-string|object|callable>
254
     */
255 29
    public function externalServices(): array
256
    {
257 29
        return array_merge(
258 29
            parent::externalServices(),
259 29
            $this->externalServices ?? [],
260 29
        );
261
    }
262
263 93
    public function setShouldResetInMemoryCache(?bool $flag): self
264
    {
265 93
        $this->markPropertyChanged(self::shouldResetInMemoryCache, $flag);
266 93
        $this->shouldResetInMemoryCache = $flag ?? self::DEFAULT_SHOULD_RESET_IN_MEMORY_CACHE;
267
268 93
        return $this;
269
    }
270
271 107
    public function shouldResetInMemoryCache(): bool
272
    {
273 107
        return (bool)$this->shouldResetInMemoryCache;
274
    }
275
276 52
    public function isFileCacheEnabled(): bool
277
    {
278 52
        return (bool)$this->fileCacheEnabled;
279
    }
280
281 7
    public function getFileCacheDirectory(): string
282
    {
283 7
        return (string)$this->fileCacheDirectory;
284
    }
285
286 93
    public function setFileCacheDirectory(?string $dir): self
287
    {
288 93
        $this->markPropertyChanged(self::fileCacheDirectory, $dir);
289 93
        $this->fileCacheDirectory = $dir ?? self::DEFAULT_FILE_CACHE_DIRECTORY;
290
291 93
        return $this;
292
    }
293
294
    /**
295
     * @param ?list<string> $list
296
     */
297 93
    public function setProjectNamespaces(?array $list): self
298
    {
299 93
        $this->markPropertyChanged(self::projectNamespaces, $list);
300 93
        $this->projectNamespaces = $list ?? self::DEFAULT_PROJECT_NAMESPACES;
301
302 93
        return $this;
303
    }
304
305
    /**
306
     * @return list<string>
307
     */
308 48
    public function getProjectNamespaces(): array
309
    {
310 48
        return (array)$this->projectNamespaces;
311
    }
312
313
    /**
314
     * @return array<string,mixed>
315
     */
316 107
    public function getConfigKeyValues(): array
317
    {
318 107
        return (array)$this->configKeyValues;
319
    }
320
321 73
    public function getEventDispatcher(): EventDispatcherInterface
322
    {
323 73
        return $this->eventDispatcher ??= SetupEventDispatcher::getDispatcher($this);
324
    }
325
326
    /**
327
     * @return array<string,list<Closure>>
328
     */
329 120
    public function getServicesToExtend(): array
330
    {
331 120
        return (array)$this->servicesToExtend;
332
    }
333
334 93
    public function setFileCacheEnabled(?bool $flag): self
335
    {
336 93
        $this->markPropertyChanged(self::fileCacheEnabled, $flag);
337 93
        $this->fileCacheEnabled = $flag ?? self::DEFAULT_FILE_CACHE_ENABLED;
338
339 93
        return $this;
340
    }
341
342 73
    public function canCreateEventDispatcher(): bool
343
    {
344 73
        return $this->areEventListenersEnabled
345 73
            && $this->hasEventListeners();
346
    }
347
348
    /**
349
     * @param ?array<string,mixed> $configKeyValues
350
     */
351 93
    public function setConfigKeyValues(?array $configKeyValues): self
352
    {
353 93
        $this->markPropertyChanged(self::configKeyValues, $configKeyValues);
354 93
        $this->configKeyValues = $configKeyValues ?? self::DEFAULT_CONFIG_KEY_VALUES;
355
356 93
        return $this;
357
    }
358
359
    /**
360
     * @return array<class-string,list<callable>>|null
361
     */
362 16
    public function getSpecificListeners(): ?array
363
    {
364 16
        return $this->specificListeners;
365
    }
366
367
    /**
368
     * @return list<callable>|null
369
     */
370 16
    public function getGenericListeners(): ?array
371
    {
372 16
        return $this->genericListeners;
373
    }
374
375 29
    public function isPropertyChanged(string $name): bool
376
    {
377 29
        return $this->changedProperties[$name] ?? false;
378
    }
379
380 29
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): self
381
    {
382 29
        $this->eventDispatcher = $eventDispatcher;
383
384 29
        return $this;
385
    }
386
387 29
    public function combine(self $other): self
388
    {
389 29
        return (new SetupCombinator($this))->combine($other);
390
    }
391
392
    /**
393
     * @param list<Closure> $servicesToExtend
394
     */
395 1
    public function addServicesToExtend(string $serviceId, array $servicesToExtend): self
396
    {
397 1
        $this->servicesToExtend[$serviceId] ??= [];
398 1
        $this->servicesToExtend[$serviceId] = [...$this->servicesToExtend[$serviceId], ...$servicesToExtend];
399 1
400 1
        return $this;
401 1
    }
402
403 1
    public function combineExternalServices(array $list): void
404
    {
405
        $this->setExternalServices(array_merge($this->externalServices ?? [], $list));
406 29
    }
407
408 29
    public function combineProjectNamespaces(array $list): void
409
    {
410
        $this->setProjectNamespaces(array_merge($this->projectNamespaces ?? [], $list));
411 1
    }
412
413 1
    public function combineConfigKeyValues(array $list): void
414
    {
415
        $this->setConfigKeyValues(array_merge($this->configKeyValues ?? [], $list));
416 1
    }
417
418 1
    /**
419
     * @param list<class-string> $list
420
     */
421
    public function combineGacelaConfigsToExtend(array $list): void
422
    {
423
        $this->setGacelaConfigsToExtend(
424 1
            array_unique(array_merge($this->gacelaConfigsToExtend ?? [], $list)),
425
        );
426 1
    }
427 1
428 1
    /**
429
     * @param list<class-string|callable> $list
430
     */
431
    public function combinePlugins(array $list): void
432
    {
433
        $this->setPlugins(array_merge($this->plugins ?? [], $list));
434 1
    }
435
436 1
    /**
437
     * @return list<class-string>
438
     */
439
    public function getGacelaConfigsToExtend(): array
440
    {
441
        return (array)$this->gacelaConfigsToExtend;
442 1
    }
443
444 1
    /**
445
     * @return list<class-string|callable>
446
     */
447
    public function getPlugins(): array
448
    {
449
        return (array)$this->plugins;
450 107
    }
451
452 107
    private function setAreEventListenersEnabled(?bool $flag): self
453
    {
454
        $this->areEventListenersEnabled = $flag ?? self::DEFAULT_ARE_EVENT_LISTENERS_ENABLED;
455 93
456
        return $this;
457 93
    }
458
459 93
    private function hasEventListeners(): bool
460
    {
461
        return ($this->genericListeners !== null && $this->genericListeners !== [])
462 70
            || ($this->specificListeners !== null && $this->specificListeners !== []);
463
    }
464 70
465 70
    /**
466
     * @param ?list<callable> $listeners
467
     */
468
    private function setGenericListeners(?array $listeners): self
469
    {
470
        $this->genericListeners = $listeners ?? self::DEFAULT_GENERIC_LISTENERS;
471 93
472
        return $this;
473 93
    }
474
475 93
    /**
476
     * @param ?array<string,list<Closure>> $list
477
     */
478
    private function setServicesToExtend(?array $list): self
479
    {
480
        $this->markPropertyChanged(self::servicesToExtend, $list);
481 93
        $this->servicesToExtend = $list ?? self::DEFAULT_SERVICES_TO_EXTEND;
482
483 93
        return $this;
484 93
    }
485
486 93
    /**
487
     * @param ?list<class-string> $list
488
     */
489
    private function setGacelaConfigsToExtend(?array $list): self
490
    {
491
        $this->markPropertyChanged(self::gacelaConfigsToExtend, $list);
492 93
        $this->gacelaConfigsToExtend = $list ?? self::DEFAULT_GACELA_CONFIGS_TO_EXTEND;
493
494 93
        return $this;
495 93
    }
496
497 93
    /**
498
     * @param ?list<class-string|callable> $list
499
     */
500
    private function setPlugins(?array $list): self
501
    {
502
        $this->markPropertyChanged(self::plugins, $list);
503 93
        $this->plugins = $list ?? self::DEFAULT_PLUGINS;
504
505 93
        return $this;
506 93
    }
507
508 93
    /**
509
     * @param ?array<class-string,list<callable>> $listeners
510
     */
511
    private function setSpecificListeners(?array $listeners): self
512
    {
513
        $this->specificListeners = $listeners ?? self::DEFAULT_SPECIFIC_LISTENERS;
514 93
515
        return $this;
516 93
    }
517
518 93
    private function markPropertyChanged(string $name, mixed $value): void
519
    {
520
        $this->changedProperties[$name] = ($value !== null);
521 96
    }
522
}
523