|
3 | 3 | namespace Dotenv;
|
4 | 4 |
|
5 | 5 | use Dotenv\Exception\InvalidPathException;
|
| 6 | +use Dotenv\File\Paths; |
| 7 | +use Dotenv\File\Reader; |
6 | 8 | use Dotenv\Loader\Loader;
|
7 | 9 | use Dotenv\Loader\LoaderInterface;
|
8 | 10 | use Dotenv\Repository\RepositoryBuilder;
|
@@ -32,93 +34,110 @@ class Dotenv
|
32 | 34 | */
|
33 | 35 | protected $filePaths;
|
34 | 36 |
|
| 37 | + /** |
| 38 | + * Should file loading short circuit? |
| 39 | + * |
| 40 | + * @var bool |
| 41 | + */ |
| 42 | + protected $shortCircuit; |
| 43 | + |
35 | 44 | /**
|
36 | 45 | * Create a new dotenv instance.
|
37 | 46 | *
|
38 | 47 | * @param \Dotenv\Loader\LoaderInterface $loader
|
39 | 48 | * @param \Dotenv\Repository\RepositoryInterface $repository
|
40 | 49 | * @param string[] $filePaths
|
| 50 | + * @param bool $shortCircuit |
41 | 51 | *
|
42 | 52 | * @return void
|
43 | 53 | */
|
44 |
| - public function __construct(LoaderInterface $loader, RepositoryInterface $repository, array $filePaths) |
| 54 | + public function __construct(LoaderInterface $loader, RepositoryInterface $repository, array $filePaths, $shortCircuit = true) |
45 | 55 | {
|
46 | 56 | $this->loader = $loader;
|
47 | 57 | $this->repository = $repository;
|
48 | 58 | $this->filePaths = $filePaths;
|
| 59 | + $this->shortCircuit = $shortCircuit; |
49 | 60 | }
|
50 | 61 |
|
51 | 62 | /**
|
52 | 63 | * Create a new dotenv instance.
|
53 | 64 | *
|
54 | 65 | * @param \Dotenv\Repository\RepositoryInterface $repository
|
55 | 66 | * @param string|string[] $paths
|
56 |
| - * @param string|null $file |
| 67 | + * @param string|string[]|null $names |
| 68 | + * @param bool $shortCircuit |
57 | 69 | *
|
58 | 70 | * @return \Dotenv\Dotenv
|
59 | 71 | */
|
60 |
| - public static function create(RepositoryInterface $repository, $paths, $file = null) |
| 72 | + public static function create(RepositoryInterface $repository, $paths, $names = null, $shortCircuit = true) |
61 | 73 | {
|
62 |
| - return new self(new Loader(), $repository, self::getFilePaths((array) $paths, $file ?: '.env')); |
| 74 | + $files = Paths::filePaths((array) $paths, (array) ($names ?: '.env')); |
| 75 | + |
| 76 | + return new self(new Loader(), $repository, $files, $shortCircuit); |
63 | 77 | }
|
64 | 78 |
|
65 | 79 | /**
|
66 | 80 | * Create a new mutable dotenv instance with default repository.
|
67 | 81 | *
|
68 |
| - * @param string|string[] $paths |
69 |
| - * @param string|null $file |
| 82 | + * @param string|string[] $paths |
| 83 | + * @param string|string[]|null $names |
| 84 | + * @param bool $shortCircuit |
70 | 85 | *
|
71 | 86 | * @return \Dotenv\Dotenv
|
72 | 87 | */
|
73 |
| - public static function createMutable($paths, $file = null) |
| 88 | + public static function createMutable($paths, $names = null, $shortCircuit = true) |
74 | 89 | {
|
75 | 90 | $repository = RepositoryBuilder::create()->make();
|
76 | 91 |
|
77 |
| - return self::create($repository, $paths, $file); |
| 92 | + return self::create($repository, $paths, $names, $shortCircuit); |
78 | 93 | }
|
79 | 94 |
|
80 | 95 | /**
|
81 | 96 | * Create a new immutable dotenv instance with default repository.
|
82 | 97 | *
|
83 |
| - * @param string|string[] $paths |
84 |
| - * @param string|null $file |
| 98 | + * @param string|string[] $paths |
| 99 | + * @param string|string[]|null $names |
| 100 | + * @param bool $shortCircuit |
85 | 101 | *
|
86 | 102 | * @return \Dotenv\Dotenv
|
87 | 103 | */
|
88 |
| - public static function createImmutable($paths, $file = null) |
| 104 | + public static function createImmutable($paths, $names = null, $shortCircuit = true) |
89 | 105 | {
|
90 | 106 | $repository = RepositoryBuilder::create()->immutable()->make();
|
91 | 107 |
|
92 |
| - return self::create($repository, $paths, $file); |
| 108 | + return self::create($repository, $paths, $names, $shortCircuit); |
93 | 109 | }
|
94 | 110 |
|
95 | 111 | /**
|
96 |
| - * Load environment file in given directory. |
| 112 | + * Read and load environment file(s). |
97 | 113 | *
|
98 | 114 | * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
|
99 | 115 | *
|
100 |
| - * @return array<string|null> |
| 116 | + * @return array<string,string|null> |
101 | 117 | */
|
102 | 118 | public function load()
|
103 | 119 | {
|
104 |
| - return $this->loader->load($this->repository, self::findAndRead($this->filePaths)); |
| 120 | + if ($this->filePaths === []) { |
| 121 | + throw new InvalidPathException('At least one environment file path must be provided.'); |
| 122 | + } |
| 123 | + |
| 124 | + return $this->tryLoad()->getOrCall(function () { |
| 125 | + throw new InvalidPathException( |
| 126 | + sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $this->filePaths)) |
| 127 | + ); |
| 128 | + }); |
105 | 129 | }
|
106 | 130 |
|
107 | 131 | /**
|
108 |
| - * Load environment file in given directory, silently failing if it doesn't exist. |
| 132 | + * Read and load environment file(s), silently failing if no files can be read. |
109 | 133 | *
|
110 | 134 | * @throws \Dotenv\Exception\InvalidFileException
|
111 | 135 | *
|
112 |
| - * @return array<string|null> |
| 136 | + * @return array<string,string|null> |
113 | 137 | */
|
114 | 138 | public function safeLoad()
|
115 | 139 | {
|
116 |
| - try { |
117 |
| - return $this->load(); |
118 |
| - } catch (InvalidPathException $e) { |
119 |
| - // suppressing exception |
120 |
| - return []; |
121 |
| - } |
| 140 | + return $this->tryLoad()->getOrElse([]); |
122 | 141 | }
|
123 | 142 |
|
124 | 143 | /**
|
@@ -146,58 +165,34 @@ public function ifPresent($variables)
|
146 | 165 | }
|
147 | 166 |
|
148 | 167 | /**
|
149 |
| - * Returns the full paths to the files. |
| 168 | + * Read and load environment file(s), returning an option. |
150 | 169 | *
|
151 |
| - * @param string[] $paths |
152 |
| - * @param string $file |
| 170 | + * @throws \Dotenv\Exception\InvalidFileException |
153 | 171 | *
|
154 |
| - * @return string[] |
| 172 | + * @return \PhpOption\Option |
155 | 173 | */
|
156 |
| - private static function getFilePaths(array $paths, $file) |
| 174 | + private function tryLoad() |
157 | 175 | {
|
158 |
| - return array_map(function ($path) use ($file) { |
159 |
| - return rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file; |
160 |
| - }, $paths); |
| 176 | + return self::aggregate(Reader::read($this->filePaths, $this->shortCircuit))->map(function ($content) { |
| 177 | + return $this->loader->load($this->repository, $content); |
| 178 | + }); |
161 | 179 | }
|
162 | 180 |
|
163 | 181 | /**
|
164 |
| - * Attempt to read the files in order. |
165 |
| - * |
166 |
| - * @param string[] $filePaths |
| 182 | + * Aggregate the given raw file contents. |
167 | 183 | *
|
168 |
| - * @throws \Dotenv\Exception\InvalidPathException |
| 184 | + * @param array<string,string> $contents |
169 | 185 | *
|
170 |
| - * @return string[] |
| 186 | + * @return \PhpOption\Option |
171 | 187 | */
|
172 |
| - private static function findAndRead(array $filePaths) |
| 188 | + private static function aggregate(array $contents) |
173 | 189 | {
|
174 |
| - if ($filePaths === []) { |
175 |
| - throw new InvalidPathException('At least one environment file path must be provided.'); |
176 |
| - } |
| 190 | + $output = ''; |
177 | 191 |
|
178 |
| - foreach ($filePaths as $filePath) { |
179 |
| - $lines = self::readFromFile($filePath); |
180 |
| - if ($lines->isDefined()) { |
181 |
| - return $lines->get(); |
182 |
| - } |
| 192 | + foreach ($contents as $content) { |
| 193 | + $output .= $content."\n"; |
183 | 194 | }
|
184 | 195 |
|
185 |
| - throw new InvalidPathException( |
186 |
| - sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $filePaths)) |
187 |
| - ); |
188 |
| - } |
189 |
| - |
190 |
| - /** |
191 |
| - * Read the given file. |
192 |
| - * |
193 |
| - * @param string $filePath |
194 |
| - * |
195 |
| - * @return \PhpOption\Option |
196 |
| - */ |
197 |
| - private static function readFromFile($filePath) |
198 |
| - { |
199 |
| - $content = @file_get_contents($filePath); |
200 |
| - |
201 |
| - return Option::fromValue($content, false); |
| 196 | + return Option::fromValue($output, ''); |
202 | 197 | }
|
203 | 198 | }
|
0 commit comments