Config::getDefaultCacheDir()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 24
ccs 0
cts 0
cp 0
rs 9.5222
cc 5
nc 5
nop 0
crap 30
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\Config;
6
7
use Gacela\Framework\Bootstrap\SetupGacelaInterface;
8
use Gacela\Framework\Event\Dispatcher\EventDispatcherInterface;
9
use Gacela\Framework\Exception\ConfigException;
10
use RuntimeException;
11
12
use function array_key_exists;
13
14
final class Config implements ConfigInterface
15
{
16
    private static ?self $instance = null;
17
18
    private static ?EventDispatcherInterface $eventDispatcher = null;
19
20
    private ?ConfigFactory $configFactory = null;
21
22
    private ?string $appRootDir = null;
23
24
    /** @var array<string,mixed> */
25
    private array $config = [];
26
27 106
    private ?string $cacheDir = null;
28
29
    private function __construct(
30 106
        private readonly SetupGacelaInterface $setup,
31
    ) {
32 106
    }
33
34 106
    public static function createWithSetup(SetupGacelaInterface $setup): self
35
    {
36 106
        self::$instance = new self($setup);
37
38
        return self::$instance;
39 89
    }
40
41 89
    public static function getInstance(): self
42
    {
43
        if (!self::$instance instanceof self) {
44
            throw new RuntimeException('You have to call createWithSetup() first. Have you forgot to bootstrap Gacela?');
45 89
        }
46
47
        return self::$instance;
48
    }
49
50
    /**
51 58
     * @internal
52
     */
53 58
    public static function resetInstance(): void
54 58
    {
55
        self::$instance = null;
56
        self::$eventDispatcher = null;
57 89
    }
58
59 89
    public static function getEventDispatcher(): EventDispatcherInterface
60 55
    {
61 55
        if (!self::$eventDispatcher instanceof EventDispatcherInterface) {
62 55
            self::$eventDispatcher = self::getInstance()
63
                ->getSetupGacela()
64
                ->getEventDispatcher();
65 89
        }
66
67
        return self::$eventDispatcher;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::eventDispatcher could return the type null which is incompatible with the type-hinted return Gacela\Framework\Event\D...ventDispatcherInterface. Consider adding an additional type-check to rule them out.
Loading history...
68
    }
69
70
    /**
71 24
     * @throws ConfigException
72
     */
73 24
    public function get(string $key, mixed $default = self::DEFAULT_CONFIG_VALUE): mixed
74 3
    {
75
        if ($this->config === []) {
76
            $this->init();
77 24
        }
78 2
79
        if ($default !== self::DEFAULT_CONFIG_VALUE && !$this->hasKey($key)) {
80
            return $default;
81 22
        }
82 1
83
        if (!$this->hasKey($key)) {
84
            throw ConfigException::keyNotFound($key, self::class);
85 21
        }
86
87
        return $this->config[$key];
88
    }
89
90
    /**
91
     * Force loading all config values in memory.
92
     *
93 106
     * @throws ConfigException
94
     */
95 106
    public function init(): void
96 106
    {
97 106
        $this->configFactory = null;
98
99
        /** @psalm-suppress DuplicateArrayKey */
100 106
        $this->config = [
101
            ...$this->loadAllConfigValues(),
102 106
            ...$this->setup->getConfigKeyValues(),
103
        ];
104 106
    }
105
106
    public function setAppRootDir(string $dir): self
107
    {
108 106
        $this->appRootDir = rtrim($dir, DIRECTORY_SEPARATOR);
109
110
        if ($this->appRootDir === '' || $this->appRootDir === '0') {
111 106
            $this->appRootDir = getcwd() ?: ''; // @codeCoverageIgnore
112
        }
113 106
114
        return $this;
115
    }
116 5
117
    public function getAppRootDir(): string
118 5
    {
119 5
        return $this->appRootDir ?? getcwd() ?: '';
120 5
    }
121
122
    public function getCacheDir(): string
123
    {
124
        if ($this->cacheDir !== null) {
125
            return $this->cacheDir;
126 106
        }
127
128 106
        $this->cacheDir = getenv('GACELA_CACHE_DIR') ?: $this->getDefaultCacheDir();
129 106
130 106
        return rtrim($this->cacheDir, DIRECTORY_SEPARATOR);
131 106
    }
132 106
133
    /**
134
     * @internal
135 106
     */
136
    public function getFactory(): ConfigFactory
137
    {
138 106
        if (!$this->configFactory instanceof ConfigFactory) {
139
            $this->configFactory = new ConfigFactory(
140 106
                $this->getAppRootDir(),
141
                $this->setup,
142
            );
143 57
        }
144
145 57
        return $this->configFactory;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->configFactory could return the type null which is incompatible with the type-hinted return Gacela\Framework\Config\ConfigFactory. Consider adding an additional type-check to rule them out.
Loading history...
146
    }
147
148
    public function getSetupGacela(): SetupGacelaInterface
149
    {
150
        return $this->setup;
151 106
    }
152
153 106
    public function hasKey(string $key): bool
154 106
    {
155 106
        return array_key_exists($key, $this->config);
156
    }
157
158
    private function getDefaultCacheDir(): string
159
    {
160
        $cacheDir = $this->setup->getFileCacheDirectory();
161
        if ($cacheDir === '') {
162
            return sys_get_temp_dir();
163
        }
164
165
        $appRoot = $this->getAppRootDir();
166
167
        if (preg_match('#^[A-Za-z]:[\\/]#', $cacheDir) === 1) {
168
            return $cacheDir;
169
        }
170
171
        if ($cacheDir[0] === DIRECTORY_SEPARATOR) {
172
            if (str_starts_with($cacheDir, $appRoot . DIRECTORY_SEPARATOR)) {
173
                return $cacheDir;
174
            }
175
176
            return $appRoot . $cacheDir;
177
        }
178
179
        return $appRoot
180
            . DIRECTORY_SEPARATOR
181
            . ltrim($cacheDir, DIRECTORY_SEPARATOR);
182
    }
183
184
    /**
185
     * @return array<string,mixed>
186
     */
187
    private function loadAllConfigValues(): array
188
    {
189
        return $this->getFactory()
190
            ->createConfigLoader()
191
            ->loadAll();
192
    }
193
}
194