ConfigAggregator::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.9666
cc 3
nc 3
nop 3
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antidot\SymfonyConfigTranslator\Container\Config;
6
7
use Antidot\SymfonyConfigTranslator\AliasTranslator;
8
use Antidot\SymfonyConfigTranslator\ConditionalTranslator;
9
use Antidot\SymfonyConfigTranslator\FactoryTranslator;
10
use Antidot\SymfonyConfigTranslator\InvokableTranslator;
11
use Antidot\SymfonyConfigTranslator\TagTranslator;
12
use DateTimeImmutable;
13
use RuntimeException;
14
use Laminas\ConfigAggregator\ConfigAggregator as BaseAggregator;
15
16
use function array_replace_recursive;
17
use function date;
18
use function file_exists;
19
use function file_put_contents;
20
use function get_class;
21
use function is_string;
22
use function json_decode;
23
use function json_encode;
24
use function sprintf;
25
use function str_replace;
26
use function var_export;
27
28
class ConfigAggregator extends BaseAggregator
29
{
30
    public const CACHE_TEMPLATE = <<< 'EOT'
31
<?php
32
/**
33
 * This configuration cache file was generated by %s
34
 * at %s
35
 */
36
return %s;
37
38
EOT;
39
40
    private array $config;
41
42 4
    public function __construct(array $providers = [], $cachedConfigFile = null, array $postProcessors = [])
43
    {
44 4
        if (is_string($cachedConfigFile)) {
45 2
            if (file_exists($cachedConfigFile)) {
46 1
                $this->config = include $cachedConfigFile;
47 1
                return;
48
            }
49 2
            parent::__construct($providers);
50 2
            $this->checkCacheConfig($cachedConfigFile);
51
        } else {
52 2
            parent::__construct($providers, $cachedConfigFile, $postProcessors);
53 2
            $this->config = $this->mergeConfig(parent::getMergedConfig());
54
        }
55 4
    }
56
57 4
    public function getMergedConfig(): array
58
    {
59 4
        return $this->config;
60
    }
61
62 2
    private function checkCacheConfig(string $cachedConfigFile): void
63
    {
64 2
        $this->config = $this->mergeConfig(parent::getMergedConfig());
65
66 2
        $this->cacheConfig(
67 2
            $this->config,
68
            $cachedConfigFile
69
        );
70 2
    }
71
72 4
    private function parse(array $defaultConfig): array
73
    {
74 4
        $config = array_replace_recursive(
75 4
            (new TagTranslator())->process($defaultConfig['services']),
76 4
            (new FactoryTranslator())->process($defaultConfig),
77 4
            (new ConditionalTranslator())->process($defaultConfig),
78 4
            (new InvokableTranslator())->process($defaultConfig['services']),
79 4
            (new AliasTranslator())->process($defaultConfig['services']),
80 4
            $defaultConfig
81
        ) ?? [];
82 4
        $config = array_replace_recursive($config, $config['dependencies'] ?? []);
83 4
        unset($config['dependencies']);
84
85 4
        return $config ?? [];
86
    }
87
88 2
    private function cacheConfig(array $config, string $cachedConfigFile): void
89
    {
90 2
        if (true === $config['config_cache_enabled']) {
91 2
            if ($this->canNotCreateCacheDirectory($cachedConfigFile)) {
92
                throw new RuntimeException(sprintf(
93
                    'Cache file "%s" was not created, because cannot create cache directory',
94
                    $cachedConfigFile
95
                ));
96
            }
97
98 2
            file_put_contents($cachedConfigFile, sprintf(
99 2
                self::CACHE_TEMPLATE,
100 2
                get_class($this),
101 2
                date('c'),
102 2
                var_export($config, true)
103
            ));
104
        }
105 2
    }
106
107 4
    private function mergeConfig(array $config): array
108
    {
109 4
        if (false === empty($config['parameters'])) {
110 1
            $config['parameters'] = json_decode(
111 1
                str_replace(
112 1
                    '%date%',
113 1
                    (new DateTimeImmutable())->format('Y-m-d'),
114 1
                    json_encode($config['parameters']) ?: ''
115
                ),
116 1
                true,
117 1
                16,
118 1
                JSON_THROW_ON_ERROR
119
            );
120 1
            $config = array_replace_recursive($config, $config['parameters'] ?? []);
121 1
            unset($config['parameters']);
122
        }
123
124 4
        return $this->parse($config ?? []);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->parse($config ?? array()) returns the type array which is incompatible with the return type mandated by Laminas\ConfigAggregator...gregator::mergeConfig() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
125
    }
126
127 2
    private function canNotCreateCacheDirectory(string $cachedConfigFile): bool
128
    {
129 2
        $concurrentDirectory = dirname($cachedConfigFile);
130 2
        if (file_exists($cachedConfigFile) || is_dir($concurrentDirectory)) {
131 2
            return false;
132
        }
133
134
        return !mkdir($concurrentDirectory, 0755, true)
135
            && !is_dir($concurrentDirectory);
136
    }
137
}
138