Passed
Push — feat/default-cache-dir ( ea747b )
by Chema
04:40
created

Config::getDefaultCacheDir()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
dl 0
loc 9
rs 10
c 1
b 0
f 0
cc 2
nc 2
nop 0
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
    private ?string $cacheDir = null;
28
29
    private function __construct(
30
        private readonly SetupGacelaInterface $setup,
31
    ) {
32
    }
33
34
    public static function createWithSetup(SetupGacelaInterface $setup): self
35
    {
36
        self::$instance = new self($setup);
37
38
        return self::$instance;
39
    }
40
41
    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
        }
46
47
        return self::$instance;
48
    }
49
50
    /**
51
     * @internal
52
     */
53
    public static function resetInstance(): void
54
    {
55
        self::$instance = null;
56
        self::$eventDispatcher = null;
57
    }
58
59
    public static function getEventDispatcher(): EventDispatcherInterface
60
    {
61
        if (!self::$eventDispatcher instanceof EventDispatcherInterface) {
62
            self::$eventDispatcher = self::getInstance()
63
                ->getSetupGacela()
64
                ->getEventDispatcher();
65
        }
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
     * @throws ConfigException
72
     */
73
    public function get(string $key, mixed $default = self::DEFAULT_CONFIG_VALUE): mixed
74
    {
75
        if ($this->config === []) {
76
            $this->init();
77
        }
78
79
        if ($default !== self::DEFAULT_CONFIG_VALUE && !$this->hasKey($key)) {
80
            return $default;
81
        }
82
83
        if (!$this->hasKey($key)) {
84
            throw ConfigException::keyNotFound($key, self::class);
85
        }
86
87
        return $this->config[$key];
88
    }
89
90
    /**
91
     * Force loading all config values in memory.
92
     *
93
     * @throws ConfigException
94
     */
95
    public function init(): void
96
    {
97
        $this->configFactory = null;
98
99
        /** @psalm-suppress DuplicateArrayKey */
100
        $this->config = [
101
            ...$this->loadAllConfigValues(),
102
            ...$this->setup->getConfigKeyValues(),
103
        ];
104
    }
105
106
    public function setAppRootDir(string $dir): self
107
    {
108
        $this->appRootDir = rtrim($dir, DIRECTORY_SEPARATOR);
109
110
        if ($this->appRootDir === '' || $this->appRootDir === '0') {
111
            $this->appRootDir = getcwd() ?: ''; // @codeCoverageIgnore
112
        }
113
114
        return $this;
115
    }
116
117
    public function getAppRootDir(): string
118
    {
119
        return $this->appRootDir ?? getcwd() ?: '';
120
    }
121
122
    public function getCacheDir(): string
123
    {
124
        if ($this->cacheDir !== null) {
125
            return $this->cacheDir;
126
        }
127
128
        $this->cacheDir = getenv('GACELA_CACHE_DIR') ?: $this->getDefaultCacheDir();
129
130
        return rtrim($this->cacheDir, DIRECTORY_SEPARATOR);
131
    }
132
133
    /**
134
     * @internal
135
     */
136
    public function getFactory(): ConfigFactory
137
    {
138
        if (!$this->configFactory instanceof ConfigFactory) {
139
            $this->configFactory = new ConfigFactory(
140
                $this->getAppRootDir(),
141
                $this->setup,
142
            );
143
        }
144
145
        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
    }
152
153
    public function hasKey(string $key): bool
154
    {
155
        return array_key_exists($key, $this->config);
156
    }
157
158
    private function getDefaultCacheDir(): string
159
    {
160
        if ($this->setup->getFileCacheDirectory() === '') {
161
            return sys_get_temp_dir();
162
        }
163
164
        return $this->getAppRootDir()
165
            . DIRECTORY_SEPARATOR
166
            . ltrim($this->setup->getFileCacheDirectory(), DIRECTORY_SEPARATOR);
167
    }
168
169
    /**
170
     * @return array<string,mixed>
171
     */
172
    private function loadAllConfigValues(): array
173
    {
174
        return $this->getFactory()
175
            ->createConfigLoader()
176
            ->loadAll();
177
    }
178
}
179