Completed
Push — master ( f84b1b...3c5fbc )
by Arman
14s
created

Environment::getEnvFilePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
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
     * Creates or updates the row in .env
174
     * @param string $key
175
     * @param string|null $value
176
     * @return void
177
     * @throws BaseException
178
     * @throws DiException
179
     * @throws EnvException
180
     * @throws ReflectionException
181
     * @throws ConfigException
182
     */
183
    public function updateRow(string $key, ?string $value)
184
    {
185
        if (!$this->isMutable) {
186
            throw EnvException::environmentImmutable();
187
        }
188
189
        if (!$this->loaded) {
190
            throw EnvException::environmentNotLoaded();
191
        }
192
193
        $envFilePath = $this->getEnvFilePath();
194
        $row = $this->getRow($key);
195
196
        if ($row) {
197
            $envFileContent = fs()->get($envFilePath);
198
            $envFileContent = preg_replace('/^' . preg_quote($row, '/') . '/m', $key . '=' . $value, $envFileContent);
199
200
            fs()->put($envFilePath, $envFileContent);
201
        } else {
202
            fs()->append($envFilePath, PHP_EOL . $key . '=' . $value . PHP_EOL);
203
        }
204
205
        $this->envContent = $this->loadDotenvFile(true);
206
    }
207
208
    /**
209
     * Finds the row by provided key
210
     * @param string $key
211
     * @return string|null
212
     */
213
    private function findKeyRow(string $key): ?string
214
    {
215
        foreach ($this->envContent as $index => $row) {
216
            if (preg_match('/^' . $key . '/', $index)) {
217
                return $key . '=' . preg_quote($row, '/');
218
            }
219
        }
220
221
        return null;
222
    }
223
224
    /**
225
     * @param bool $forceMutableReload
226
     * @return array
227
     */
228
    private function loadDotenvFile(bool $forceMutableReload = false): array
229
    {
230
        $baseDir = App::getBaseDir();
231
232
        $dotenv = ($forceMutableReload || $this->isMutable)
233
            ? Dotenv::createMutable($baseDir, $this->envFile)
234
            : Dotenv::createImmutable($baseDir, $this->envFile);
235
236
        $loadedVars = $dotenv->load();
237
238
        return is_array($loadedVars) ? $loadedVars : [];
0 ignored issues
show
introduced by
The condition is_array($loadedVars) is always true.
Loading history...
239
    }
240
241
    /**
242
     * @return string
243
     */
244
    private function getEnvFilePath(): string
245
    {
246
        return App::getBaseDir() . DS . $this->envFile;
247
    }
248
}
249