Passed
Push — master ( 4b3d26...06dcf5 )
by Enjoys
12:36 queued 13s
created

Dotenv::readFiles()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 9
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 14
ccs 10
cts 10
cp 1
crap 4
rs 9.9666
1
<?php
2
3
declare(strict_types=1);
4
5
6
namespace Enjoys\Dotenv;
7
8
use Enjoys\Dotenv\Parser\Parser;
9
use Enjoys\Dotenv\Parser\ParserInterface;
10
11
class Dotenv
12
{
13
14
    public const CLEAR_MEMORY_AFTER_LOAD_ENV = 1;
15
    public const CAST_TYPE_ENV_VALUE = 2;
16
    public const POPULATE_PUTENV = 4;
17
    public const POPULATE_SERVER = 8;
18
19
    private const CHARACTER_MAP = [
20
        "\\n" => "\n",
21
        "\\\"" => "\"",
22
        "\\\\" => "\\",
23
        '\\\'' => "'",
24
        '\\t' => "\t"
25
    ];
26
27
    /**
28
     * @var array<string, string|null>
29
     */
30
    private array $envRawArray = [];
31
32
    private EnvCollection $envCollection;
33
    private ParserInterface $parser;
34
    private Variables $variablesResolver;
35
    private StorageInterface $storage;
36
37 51
    public function __construct(
38
        private string $envFilePath,
39
        ?StorageInterface $storage = null,
40
        ?ParserInterface $parser = null,
41
        private int $flags = 0
42
    ) {
43 51
        $this->envCollection = new EnvCollection();
44 51
        $this->parser = $parser ?? new Parser();
45 51
        $this->storage = $storage ?? new Storage();
46 51
        $this->variablesResolver = new Variables($this);
47
    }
48
49 44
    public function loadEnv(bool $usePutEnv = false): void
50
    {
51 44
        if ($usePutEnv){
52 4
            $this->flags = $this->flags | self::POPULATE_PUTENV;
53
        }
54
55 44
        $this->readFiles();
56 42
        $this->writeEnvs();
57
58
59 40
        putenv(sprintf('ENJOYS_DOTENV=%s', implode(',', $this->envCollection->getKeys())));
60
61 40
        if ($this->isClearMemory()) {
62 1
            $this->clearMemory();
63
        }
64
    }
65
66 44
    private function readFiles(): void
67
    {
68 44
        $this->storage->addPath($this->envFilePath . '.dist');
69 44
        $this->storage->addPath($this->envFilePath);
70
71 44
        while (false !== $path = $this->storage->getPath()) {
72 43
            if ($this->storage->isLoaded($path)) {
73 10
                continue;
74
            }
75
76 43
            $this->envRawArray = array_merge($this->envRawArray, $this->parser->parseEnv(file_get_contents($path)));
77 41
            $this->storage->markLoaded($path);
78 41
            $this->storage->addPath(
79 41
                $this->envFilePath . '.' . ((getenv('APP_ENV') ?: null) ?? $this->envRawArray['APP_ENV'] ?? '')
80
            );
81
        }
82
    }
83
84 42
    private function writeEnvs(): void
85
    {
86 42
        foreach ($this->envRawArray as $key => $value) {
87 40
            $this->populate($key, $value);
88
        }
89
    }
90
91 47
    public function handleValue(string $key, ?string $value): float|bool|int|string|null
92
    {
93
94 47
        if ($value !== null) {
95 46
            $value = preg_replace_callback('/^(?<quote>[\'"])?(?<value>.*)\1/', function ($matches) {
96 24
                return match ($matches['quote']) {
97 5
                    "'" => $matches['value'],
98 24
                    "\"" => strtr($matches['value'], self::CHARACTER_MAP)
99
                };
100
            }, $value, count: $quoted);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $quoted seems to be never defined.
Loading history...
101
102
        }
103
104 47
        $value = $this->variablesResolver->resolve($key, $value);
105
106
107 46
        if (getenv($key)) {
108 8
            $value = getenv($key);
109
        }
110
111 46
        return ($this->isCastType() && ($quoted ?? null) === 0) ? Helper::castType($value) : $value;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $quoted seems to never exist and therefore isset should always be false.
Loading history...
112
    }
113
114 40
    public function populate(
115
        string $key,
116
        string|null $value,
117
    ): void {
118 40
        $value = $this->handleValue($key, $value);
119
120 39
        $_ENV[$key] = $value;
121 39
        $this->envCollection->add($key, $value);
122
123
124 39
        if (!getenv($key) && $this->isUsePutEnv() === true) {
125 5
            putenv(sprintf("%s=%s", $key, Helper::scalarValueToString($value)));
126
        }
127
128 39
        if ($this->isPopulateToServer()) {
129 1
            $_SERVER[$key] = $value;
130
        }
131
132
    }
133
134 15
    public function getEnvRawArray(): array
135
    {
136 15
        return $this->envRawArray;
137
    }
138
139 24
    public function getEnvCollection(): EnvCollection
140
    {
141 24
        return $this->envCollection;
142
    }
143
144
    /**
145
     * @return string[]
146
     */
147 3
    public function getLoadedPaths(): array
148
    {
149 3
        return $this->storage->getLoadedPaths();
150
    }
151
152
153 46
    public static function clear(): void
154
    {
155 46
        if (false !== $envs = getenv('ENJOYS_DOTENV')) {
156 33
            foreach (explode(',', $envs) as $key) {
157 33
                if (!empty($key)) {
158
                    //unset
159 31
                    putenv($key);
160 31
                    unset($_ENV[$key], $_SERVER[$key]);
161
                }
162
            }
163
        }
164 46
        putenv('ENJOYS_DOTENV');
165
    }
166
167 7
    public function enableCastType(): void
168
    {
169 7
        $this->flags = $this->flags | self::CAST_TYPE_ENV_VALUE;
170
    }
171
172 1
    public function disableCastType(): void
173
    {
174 1
        $this->flags = $this->flags ^ self::CAST_TYPE_ENV_VALUE;
175
    }
176
177 1
    private function clearMemory(): void
178
    {
179 1
        unset($this->envCollection, $this->variablesResolver);
180
    }
181
182 39
    private function isUsePutEnv(): bool
183
    {
184 39
        return ($this->flags & self::POPULATE_PUTENV) === self::POPULATE_PUTENV;
185
    }
186
187 39
    private function isPopulateToServer(): bool
188
    {
189 39
        return ($this->flags & self::POPULATE_SERVER) === self::POPULATE_SERVER;
190
    }
191
192 46
    private function isCastType(): bool
193
    {
194 46
        return ($this->flags & self::CAST_TYPE_ENV_VALUE) === self::CAST_TYPE_ENV_VALUE;
195
    }
196
197 40
    private function isClearMemory(): bool
198
    {
199 40
        return ($this->flags & self::CLEAR_MEMORY_AFTER_LOAD_ENV) === self::CLEAR_MEMORY_AFTER_LOAD_ENV;
200
    }
201
202
}
203