Passed
Push — main ( 971eef...93f486 )
by Chema
09:20 queued 05:23
created

SetupGacela::setProjectNamespaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
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\BuilderExecutor;
9
use Gacela\Framework\Bootstrap\Setup\GacelaConfigExtender;
10
use Gacela\Framework\Bootstrap\Setup\Properties;
11
use Gacela\Framework\Bootstrap\Setup\PropertyChangeTracker;
12
use Gacela\Framework\Bootstrap\Setup\PropertyMerger;
13
use Gacela\Framework\Bootstrap\Setup\SetupMerger;
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 133
        $dto = $gacelaConfig->toTransfer();
76
77 133
        return (new self())
78 74
            ->setExternalServices($dto->externalServices)
79
            ->setAppConfigBuilder($dto->appConfigBuilder)
80 133
            ->setSuffixTypesBuilder($dto->suffixTypesBuilder)
81 133
            ->setBindingsBuilder($dto->bindingsBuilder)
82 133
            ->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 74
    public function setAppConfigBuilder(AppConfigBuilder $builder): self
107
    {
108 74
        $this->properties->appConfigBuilder = $builder;
109 74
110
        return $this;
111 74
    }
112
113
    public function setSuffixTypesBuilder(SuffixTypesBuilder $builder): self
114 93
    {
115
        $this->properties->suffixTypesBuilder = $builder;
116 93
117
        return $this;
118 93
    }
119
120 93
    public function setBindingsBuilder(BindingsBuilder $builder): self
121 93
    {
122 93
        $this->properties->bindingsBuilder = $builder;
123 93
124 93
        return $this;
125 93
    }
126 93
127 93
    /**
128 93
     * @param callable(AppConfigBuilder):void $callable
129 93
     */
130 93
    public function setAppConfigFn(callable $callable): self
131 93
    {
132 93
        $this->properties->appConfigFn = $callable;
133 93
134 93
        return $this;
135 93
    }
136
137
    #[Override]
138
    public function buildAppConfig(AppConfigBuilder $builder): AppConfigBuilder
139
    {
140
        $builder = parent::buildAppConfig($builder);
141 96
142
        return $this->builderExecutor->buildAppConfig($builder);
143 96
    }
144 96
145
    /**
146 96
     * @param callable(BindingsBuilder,array<string,mixed>):void $callable
147
     */
148
    public function setBindingsFn(callable $callable): self
149 93
    {
150
        $this->properties->bindingsFn = $callable;
151 93
152
        return $this;
153 93
    }
154
155
    /**
156 93
     * Define the mapping between interfaces and concretions, so Gacela services will auto-resolve them automatically.
157
     *
158 93
     * @param array<string,class-string|object|callable> $externalServices
159
     */
160 93
    #[Override]
161
    public function buildBindings(
162
        BindingsBuilder $builder,
163 93
        array $externalServices,
164
    ): BindingsBuilder {
165 93
        $builder = parent::buildBindings($builder, $externalServices);
166
167 93
        return $this->builderExecutor->buildBindings($builder, $externalServices);
168
    }
169
170
    /**
171
     * @param callable(SuffixTypesBuilder):void $callable
172
     */
173 3
    public function setSuffixTypesFn(callable $callable): self
174
    {
175 3
        $this->properties->suffixTypesFn = $callable;
176
177 3
        return $this;
178
    }
179
180 75
    /**
181
     * Allow overriding gacela resolvable types.
182 75
     */
183
    #[Override]
184 75
    public function buildSuffixTypes(SuffixTypesBuilder $builder): SuffixTypesBuilder
185 67
    {
186
        $builder = parent::buildSuffixTypes($builder);
187
188 75
        return $this->builderExecutor->buildSuffixTypes($builder);
189
    }
190 75
191
    /**
192
     * @return array<string, class-string|object|callable>
193
     */
194
    #[Override]
195
    public function externalServices(): array
196 3
    {
197
        return array_merge(
198 3
            parent::externalServices(),
199
            $this->properties->externalServices ?? [],
200 3
        );
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 75
        return $this;
209
    }
210
211
    #[Override]
212 75
    public function shouldResetInMemoryCache(): bool
213
    {
214 75
        return (bool)$this->properties->shouldResetInMemoryCache;
215 67
    }
216
217
    #[Override]
218 75
    public function isFileCacheEnabled(): bool
219 75
    {
220 75
        return (bool)$this->properties->fileCacheEnabled;
221 75
    }
222
223 75
    #[Override]
224
    public function getFileCacheDirectory(): string
225
    {
226
        return (string)$this->properties->fileCacheDirectory;
227
    }
228
229 3
    public function setFileCacheDirectory(?string $dir): self
230
    {
231 3
        $this->markPropertyAsChanged(self::fileCacheDirectory, $dir !== null);
232
        $this->properties->fileCacheDirectory = $dir ?? self::DEFAULT_FILE_CACHE_DIRECTORY;
233 3
234
        return $this;
235
    }
236
237
    /**
238
     * @param ?list<string> $list
239 75
     */
240
    public function setProjectNamespaces(?array $list): self
241 75
    {
242
        $this->markPropertyAsChanged(self::projectNamespaces, $list !== null);
243 75
        $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 67
245
        return $this;
246
    }
247 75
248
    /**
249 75
     * @return list<string>
250
     */
251
    #[Override]
252
    public function getProjectNamespaces(): array
253
    {
254
        return (array)$this->properties->projectNamespaces;
255 29
    }
256
257 29
    /**
258 29
     * @return array<string,mixed>
259 29
     */
260 29
    #[Override]
261
    public function getConfigKeyValues(): array
262
    {
263 93
        return (array)$this->properties->configKeyValues;
264
    }
265 93
266 93
    #[Override]
267
    public function getEventDispatcher(): EventDispatcherInterface
268 93
    {
269
        return $this->properties->eventDispatcher ??= SetupEventDispatcher::getDispatcher($this);
270
    }
271 107
272
    /**
273 107
     * @return array<string,list<Closure>>
274
     */
275
    #[Override]
276 49
    public function getServicesToExtend(): array
277
    {
278 49
        return (array)$this->properties->servicesToExtend;
279
    }
280
281 7
    public function setFileCacheEnabled(?bool $flag): self
282
    {
283 7
        $this->markPropertyAsChanged(self::fileCacheEnabled, $flag !== null);
284
        $this->properties->fileCacheEnabled = $flag ?? self::DEFAULT_FILE_CACHE_ENABLED;
285
286 93
        return $this;
287
    }
288 93
289 93
    public function canCreateEventDispatcher(): bool
290
    {
291 93
        return $this->properties->areEventListenersEnabled === true
292
            && $this->hasEventListeners();
293
    }
294
295
    /**
296
     * @param ?array<string,mixed> $configKeyValues
297 93
     */
298
    public function setConfigKeyValues(?array $configKeyValues): self
299 93
    {
300 93
        $this->markPropertyAsChanged(self::configKeyValues, $configKeyValues !== null);
301
        $this->properties->configKeyValues = $configKeyValues ?? self::DEFAULT_CONFIG_KEY_VALUES;
302 93
303
        return $this;
304
    }
305
306
    /**
307
     * @return array<class-string,list<callable>>|null
308 45
     */
309
    public function getSpecificListeners(): ?array
310 45
    {
311
        return $this->properties->specificListeners;
312
    }
313
314
    /**
315
     * @return list<callable>|null
316 107
     */
317
    public function getGenericListeners(): ?array
318 107
    {
319
        return $this->properties->genericListeners;
320
    }
321 70
322
    public function isPropertyChanged(string $name): bool
323 70
    {
324
        return $this->changeTracker->isChanged($name);
325
    }
326
327
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): self
328
    {
329 120
        $this->properties->eventDispatcher = $eventDispatcher;
330
331 120
        return $this;
332
    }
333
334 93
    #[Override]
335
    public function merge(self $other): self
336 93
    {
337 93
        return (new SetupMerger($this))->merge($other);
338
    }
339 93
340
    /**
341
     * @param list<Closure> $servicesToExtend
342 70
     */
343
    public function addServicesToExtend(string $serviceId, array $servicesToExtend): self
344 70
    {
345 70
        $this->properties->servicesToExtend[$serviceId] ??= [];
346
        $this->properties->servicesToExtend[$serviceId] = [...$this->properties->servicesToExtend[$serviceId], ...$servicesToExtend];
347
348
        return $this;
349
    }
350
351 93
    /**
352
     * @param array<string,class-string|object|callable> $list
353 93
     */
354 93
    public function mergeExternalServices(array $list): void
355
    {
356 93
        (new PropertyMerger($this))->mergeExternalServices($list);
357
    }
358
359
    /**
360
     * @param list<string> $list
361
     */
362 16
    public function mergeProjectNamespaces(array $list): void
363
    {
364 16
        (new PropertyMerger($this))->mergeProjectNamespaces($list);
365
    }
366
367
    /**
368
     * @param array<string,mixed> $list
369
     */
370 16
    public function mergeConfigKeyValues(array $list): void
371
    {
372 16
        (new PropertyMerger($this))->mergeConfigKeyValues($list);
373
    }
374
375 29
    /**
376
     * @param list<class-string> $list
377 29
     */
378
    public function mergeGacelaConfigsToExtend(array $list): void
379
    {
380 29
        (new PropertyMerger($this))->mergeGacelaConfigsToExtend($list);
381
    }
382 29
383
    /**
384 29
     * @param list<class-string|callable> $list
385
     */
386
    public function mergePlugins(array $list): void
387 29
    {
388
        (new PropertyMerger($this))->mergePlugins($list);
389 29
    }
390
391
    /**
392
     * @return list<class-string>
393
     */
394
    #[Override]
395 1
    public function getGacelaConfigsToExtend(): array
396
    {
397 1
        return (array)$this->properties->gacelaConfigsToExtend;
398 1
    }
399 1
400 1
    /**
401 1
     * @return list<class-string|callable>
402
     */
403 1
    #[Override]
404
    public function getPlugins(): array
405
    {
406 29
        return (array)$this->properties->plugins;
407
    }
408 29
409
    private function setAreEventListenersEnabled(?bool $flag): self
410
    {
411 1
        $this->properties->areEventListenersEnabled = $flag ?? self::DEFAULT_ARE_EVENT_LISTENERS_ENABLED;
412
413 1
        return $this;
414
    }
415
416 1
    private function hasEventListeners(): bool
417
    {
418 1
        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 1
     */
425
    private function setGenericListeners(?array $listeners): self
426 1
    {
427 1
        $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 1
429
        return $this;
430
    }
431
432
    /**
433
     * @param ?array<string,list<Closure>> $list
434 1
     */
435
    private function setServicesToExtend(?array $list): self
436 1
    {
437
        $this->markPropertyAsChanged(self::servicesToExtend, $list !== null);
438
        $this->properties->servicesToExtend = $list ?? self::DEFAULT_SERVICES_TO_EXTEND;
439
440
        return $this;
441
    }
442 1
443
    /**
444 1
     * @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 107
451
        return $this;
452 107
    }
453
454
    /**
455 93
     * @param ?list<class-string|callable> $list
456
     */
457 93
    private function setPlugins(?array $list): self
458
    {
459 93
        $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 70
        return $this;
463
    }
464 70
465 70
    /**
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 93
472
        return $this;
473 93
    }
474
475 93
    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 93
        }
482
    }
483
}
484