Passed
Push — feature/add-config-createWithS... ( af0a2b )
by Chema
04:17
created

Config::createWithSetup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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