Passed
Pull Request — master (#410)
by Arman
03:14
created

Environment::getValue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 2
b 0
f 0
nc 3
nop 2
dl 0
loc 11
rs 10
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 3.0.0
13
 */
14
15
namespace Quantum\Environment;
16
17
use Quantum\Environment\Exceptions\EnvException;
18
use Quantum\Config\Exceptions\ConfigException;
19
use Quantum\App\Exceptions\BaseException;
20
use Quantum\Di\Exceptions\DiException;
21
use Quantum\Environment\Enums\Env;
22
use Quantum\Loader\Loader;
23
use Quantum\Loader\Setup;
24
use ReflectionException;
25
use Quantum\App\App;
26
use Dotenv\Dotenv;
27
use Quantum\Di\Di;
28
29
/**
30
 * Class Environment
31
 * @package Quantum\Environment
32
 * @uses Dotenv
33
 */
34
class Environment
35
{
36
    /**
37
     * Environment file
38
     * @var string
39
     */
40
    private string $envFile = '.env';
41
42
    /**
43
     * @var bool
44
     */
45
    private bool $isMutable = false;
46
47
    /**
48
     * Loaded env content
49
     * @var array
50
     */
51
    private array $envContent = [];
52
53
    /**
54
     * @var bool
55
     */
56
    private bool $loaded = false;
57
58
    /**
59
     * @var string
60
     */
61
    private static string $appEnv = Env::PRODUCTION;
62
63
    /**
64
     * Instance of Environment
65
     * @var Environment|null
66
     */
67
    private static ?Environment $instance = null;
68
69
    /**
70
     * GetInstance
71
     * @return Environment
72
     */
73
    public static function getInstance(): Environment
74
    {
75
        if (self::$instance === null) {
76
            self::$instance = new self();
77
        }
78
79
        return self::$instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::instance could return the type null which is incompatible with the type-hinted return Quantum\Environment\Environment. Consider adding an additional type-check to rule them out.
Loading history...
80
    }
81
82
    /**
83
     * @param bool $isMutable
84
     * @return Environment
85
     */
86
    public function setMutable(bool $isMutable): Environment
87
    {
88
        $this->isMutable = $isMutable;
89
        return $this;
90
    }
91
92
    /**
93
     * Loads environment variables from file
94
     * @param Setup $setup
95
     * @return void
96
     * @throws BaseException
97
     * @throws EnvException
98
     * @throws DiException
99
     * @throws ReflectionException
100
     */
101
    public function load(Setup $setup)
102
    {
103
        if ($this->loaded) {
104
            return;
105
        }
106
107
        $envConfig = Di::get(Loader::class)->setup($setup)->load();
108
109
        $appEnv = $envConfig['app_env'] ?? Env::PRODUCTION;
110
111
        $this->envFile = '.env' . ($appEnv !== Env::PRODUCTION ? ".$appEnv" : '');
112
113
        if (!fs()->exists($this->getEnvFilePath())) {
114
            throw EnvException::fileNotFound($this->envFile);
115
        }
116
117
        $this->envContent = $this->loadDotenvFile();
118
119
        $this->loaded = true;
120
        self::$appEnv = $appEnv;
121
    }
122
123
    /**
124
     * Gets the app current environment
125
     * @return string
126
     */
127
    public function getAppEnv(): string
128
    {
129
        return self::$appEnv;
130
    }
131
132
    /**
133
     * Gets the environment variable value
134
     * @param string $key
135
     * @param null|mixed $default
136
     * @return mixed
137
     * @throws EnvException
138
     */
139
    public function getValue(string $key, $default = null)
140
    {
141
        if (!$this->loaded) {
142
            throw EnvException::environmentNotLoaded();
143
        }
144
145
        if (array_key_exists($key, $this->envContent)) {
146
            return $this->envContent[$key];
147
        }
148
149
        return $default;
150
    }
151
152
    /**
153
     * Checks if there is a such key
154
     * @param string $key
155
     * @return bool
156
     */
157
    public function hasKey(string $key): bool
158
    {
159
        return $this->findKeyRow($key) !== null;
160
    }
161
162
    /**
163
     * Gets the row of .env file by given key
164
     * @param string $key
165
     * @return string|null
166
     */
167
    public function getRow(string $key): ?string
168
    {
169
        return $this->findKeyRow($key);
170
    }
171
172
    /**
173
     *
174
     * @param string $key
175
     * @param string|null $value
176
     * @throws EnvException
177
     */
178
179
    /**
180
     * Creates or updates the row in .env
181
     * @param string $key
182
     * @param string|null $value
183
     * @return void
184
     * @throws BaseException
185
     * @throws DiException
186
     * @throws EnvException
187
     * @throws ReflectionException
188
     * @throws ConfigException
189
     */
190
    public function updateRow(string $key, ?string $value)
191
    {
192
        if (!$this->isMutable) {
193
            throw EnvException::environmentImmutable();
194
        }
195
196
        if (!$this->loaded) {
197
            throw EnvException::environmentNotLoaded();
198
        }
199
200
        $envFilePath = $this->getEnvFilePath();
201
        $row = $this->getRow($key);
202
203
        if ($row) {
204
            $envFileContent = fs()->get($envFilePath);
205
            $envFileContent = preg_replace('/^' . preg_quote($row, '/') . '/m', $key . '=' . $value, $envFileContent);
206
207
            fs()->put($envFilePath, $envFileContent);
208
        } else {
209
            fs()->append($envFilePath, PHP_EOL . $key . '=' . $value . PHP_EOL);
210
        }
211
212
        $this->envContent = $this->loadDotenvFile(true);
213
    }
214
215
    /**
216
     * Finds the row by provided key
217
     * @param string $key
218
     * @return string|null
219
     */
220
    private function findKeyRow(string $key): ?string
221
    {
222
        foreach ($this->envContent as $index => $row) {
223
            if (preg_match('/^' . $key . '/', $index)) {
224
                return $key . '=' . preg_quote($row, '/');
225
            }
226
        }
227
228
        return null;
229
    }
230
231
    /**
232
     * @param bool $forceMutableReload
233
     * @return array
234
     */
235
    private function loadDotenvFile(bool $forceMutableReload = false): array
236
    {
237
        $baseDir = App::getBaseDir();
238
239
        $dotenv = ($forceMutableReload || $this->isMutable)
240
            ? Dotenv::createMutable($baseDir, $this->envFile)
241
            : Dotenv::createImmutable($baseDir, $this->envFile);
242
243
        $loadedVars = $dotenv->load();
244
245
        return is_array($loadedVars) ? $loadedVars : [];
0 ignored issues
show
introduced by
The condition is_array($loadedVars) is always true.
Loading history...
246
    }
247
248
    /**
249
     * @return string
250
     */
251
    private function getEnvFilePath(): string
252
    {
253
        return App::getBaseDir() . DS . $this->envFile;
254
    }
255
}
256