diff options
author | Александр Кирюхин <alexander@kiryukhin.su> | 2018-01-19 03:13:16 +0300 |
---|---|---|
committer | Александр Кирюхин <alexander@kiryukhin.su> | 2018-01-19 03:13:16 +0300 |
commit | 6f452ea995c25a30f214a530fddc6e9d236bdfce (patch) | |
tree | b6538c4e7bd600f3dd4bcaf0d1340155d95da373 /src | |
parent | 6b07f5f4ebb3043efc4991debebb14529cb77aa5 (diff) |
Completed reference implementation, added tests
Diffstat (limited to 'src')
-rw-r--r-- | src/Compiler/Compiler.php | 80 | ||||
-rw-r--r-- | src/Compiler/CompilerInterface.php | 10 | ||||
-rw-r--r-- | src/Dotenv.php | 23 | ||||
-rw-r--r-- | src/Exception/RuntimeException.php | 7 | ||||
-rw-r--r-- | src/Loader/FileLoader.php | 41 | ||||
-rw-r--r-- | src/Loader/LoaderInterface.php | 7 | ||||
-rw-r--r-- | src/Parser/Parser.php | 55 | ||||
-rw-r--r-- | src/Parser/ParserInterface.php | 6 | ||||
-rw-r--r-- | src/Types/KeyValue.php | 11 |
9 files changed, 232 insertions, 8 deletions
diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php new file mode 100644 index 0000000..6a587d2 --- /dev/null +++ b/src/Compiler/Compiler.php @@ -0,0 +1,80 @@ +<?php +declare(strict_types=1); + +/** + * @author: Alexander Kiryukhin <alexander@kiryukhin.su> + * @license: MIT + */ + +namespace NeonXP\Dotenv\Compiler; + +use NeonXP\Dotenv\Exception\RuntimeException; +use NeonXP\Dotenv\Types\KeyValue; + +/** + * Class Compiler + * @package NeonXP\Dotenv\Compiler + */ +class Compiler implements CompilerInterface +{ + const REGEX_VARIABLE = '/\$\{(.+?)\}/'; + + /** + * @var KeyValue[] + */ + protected $collection = []; + + /** + * @var KeyValue[] + */ + protected $cache = []; + + /** + * @inheritdoc + * @param KeyValue[] $collection + */ + public function setRawCollection(array $collection): void + { + $this->collection = []; + $this->cache = []; + foreach ($collection as $keyValue) { + $this->collection[$keyValue->getKey()] = $keyValue; + } + } + + /** + * @inheritdoc + * @param KeyValue $keyValue + * @return KeyValue + */ + public function compileKeyValue(KeyValue $keyValue): KeyValue + { + $newValue = preg_replace_callback(self::REGEX_VARIABLE, function ($variable) use ($keyValue) { + $variable = $variable[1]; + if ($variable === $keyValue->getKey()) { + throw new RuntimeException('Self referencing'); + } + if (isset($this->cache[$variable])) { + return $this->cache[$variable]->getValue(); + } elseif (isset($this->collection[$variable]) && !$this->needToCompile($this->collection[$variable])) { + return $this->collection[$variable]->getValue(); + } elseif (isset($this->collection[$variable]) && $this->needToCompile($this->collection[$variable])) { + return $this->compileKeyValue($this->collection[$variable])->getValue(); + } + return "UNKNOWN VARIABLE {$variable}"; + }, $keyValue->getValue()); + $result = new KeyValue($keyValue->getKey(), $newValue); + $this->cache[$result->getKey()] = $result; + + return $result; + } + + /** + * @param KeyValue $keyValue + * @return bool + */ + protected function needToCompile(KeyValue $keyValue): bool + { + return !!preg_match(self::REGEX_VARIABLE, $keyValue->getValue()); + } +}
\ No newline at end of file diff --git a/src/Compiler/CompilerInterface.php b/src/Compiler/CompilerInterface.php index 042a7d0..15b6823 100644 --- a/src/Compiler/CompilerInterface.php +++ b/src/Compiler/CompilerInterface.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -8,16 +10,20 @@ namespace NeonXP\Dotenv\Compiler; use NeonXP\Dotenv\Types\KeyValue; +/** + * Interface CompilerInterface + * @package NeonXP\Dotenv\Compiler + */ interface CompilerInterface { /** * @param KeyValue[] $collection */ - function setRawCollection(array $collection): void; + public function setRawCollection(array $collection): void; /** * @param KeyValue $keyValue * @return KeyValue */ - function compileKeyValue(KeyValue $keyValue): KeyValue; + public function compileKeyValue(KeyValue $keyValue): KeyValue; }
\ No newline at end of file diff --git a/src/Dotenv.php b/src/Dotenv.php index 8e7ac10..3f3b0c6 100644 --- a/src/Dotenv.php +++ b/src/Dotenv.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -8,10 +10,16 @@ namespace NeonXP\Dotenv; use NeonXP\Dotenv\Compiler\CompilerInterface; use NeonXP\Dotenv\Exception\RuntimeException; +use NeonXP\Dotenv\Loader\FileLoader; use NeonXP\Dotenv\Loader\LoaderInterface; +use NeonXP\Dotenv\Parser\Parser; use NeonXP\Dotenv\Parser\ParserInterface; use NeonXP\Dotenv\Types\KeyValue; +/** + * Class Dotenv + * @package NeonXP\Dotenv + */ class Dotenv implements \ArrayAccess, \IteratorAggregate { /** @@ -40,6 +48,13 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate */ public function __construct(LoaderInterface $loader = null, ParserInterface $parser = null, CompilerInterface $compiler = null) { + if (!$loader) { + $loader = new FileLoader(); // Default loader + } + if (!$parser) { + $parser = new Parser(); // Default parser + } + $this->loader = $loader; $this->parser = $parser; $this->compiler = $compiler; @@ -63,6 +78,10 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate }, [] ); + foreach ($this->loadedValues as $key => $value) { + $_ENV[$key] = $value; + putenv($key . "=" . $value); + } return $this; } @@ -85,7 +104,7 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate * @return mixed * @throws RuntimeException */ - public function get(string $key, mixed $default = null): mixed + public function get(string $key, $default = null) { if (!$this->has($key)) { return $default; @@ -122,7 +141,7 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate * @return bool * @throws RuntimeException */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return $this->has($offset); } diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index 1a9be9c..5728623 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -6,7 +8,10 @@ namespace NeonXP\Dotenv\Exception; - +/** + * Class RuntimeException + * @package NeonXP\Dotenv\Exception + */ class RuntimeException extends \Exception { diff --git a/src/Loader/FileLoader.php b/src/Loader/FileLoader.php new file mode 100644 index 0000000..0702a53 --- /dev/null +++ b/src/Loader/FileLoader.php @@ -0,0 +1,41 @@ +<?php +declare(strict_types=1); + +/** + * @author: Alexander Kiryukhin <alexander@kiryukhin.su> + * @license: MIT + */ + +namespace NeonXP\Dotenv\Loader; + +use NeonXP\Dotenv\Exception\RuntimeException; + +/** + * Class FileLoader + * @package NeonXP\Dotenv\Loader + */ +class FileLoader implements LoaderInterface +{ + const COMMENT_LINE_REGEX = '/^\s*#/'; + + /** + * @inheritdoc + * @param string $filePath + * @return array + * @throws RuntimeException + */ + public function load(string $filePath = '.env'): array + { + if (!file_exists($filePath)) { + throw new RuntimeException("There is no {$filePath} file!"); + } + $lines = file($filePath); + $lines = array_map('trim', $lines); + $lines = array_filter($lines, function (string $line) { + return trim($line) && !preg_match(self::COMMENT_LINE_REGEX, $line); + }); + $lines = array_values($lines); + + return $lines; + } +}
\ No newline at end of file diff --git a/src/Loader/LoaderInterface.php b/src/Loader/LoaderInterface.php index 1c4f166..c848e6c 100644 --- a/src/Loader/LoaderInterface.php +++ b/src/Loader/LoaderInterface.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -6,9 +8,14 @@ namespace NeonXP\Dotenv\Loader; +/** + * Interface LoaderInterface + * @package NeonXP\Dotenv\Loader + */ interface LoaderInterface { /** + * Load not empty lines from file or other source * @param string $filePath * @return string[] */ diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php new file mode 100644 index 0000000..7a5c37b --- /dev/null +++ b/src/Parser/Parser.php @@ -0,0 +1,55 @@ +<?php +declare(strict_types=1); + +/** + * @author: Alexander Kiryukhin <alexander@kiryukhin.su> + * @license: MIT + */ + +namespace NeonXP\Dotenv\Parser; + +use NeonXP\Dotenv\Types\KeyValue; + +/** + * Class Parser + * @package NeonXP\Dotenv\Parser + */ +class Parser implements ParserInterface +{ + const REGEX_EXPORT_PREFIX = '/^\s*export\s/i'; + + // Quotes and comments + const SINGLE_QUOTED_LINE_WITH_COMMENT = '/^\'(.*?)\'\s+#.*?$/i'; + const DOUBLE_QUOTED_LINE_WITH_COMMENT = '/^\"(.+?)\"\s+#.*?$/i'; + const SINGLE_QUOTED_LINE = '/^\'(.+?)\'$/i'; + const DOUBLE_QUOTED_LINE = '/^\"(.*?)\"$/i'; + + // Types + const BOOLEAN = '/^(true|false)$/i'; + const NUMBER = '/^(\d+)$/'; + + public function parseLine(string $line): KeyValue + { + $line = preg_replace(self::REGEX_EXPORT_PREFIX, '', $line); + list($key, $value) = explode('=', $line, 2) + ['', '']; + $key = trim($key); + $value = trim($value); + $matches = []; + if ( + preg_match(self::SINGLE_QUOTED_LINE_WITH_COMMENT, $value, $matches) || + preg_match(self::DOUBLE_QUOTED_LINE_WITH_COMMENT, $value, $matches) || + preg_match(self::SINGLE_QUOTED_LINE, $value, $matches) || + preg_match(self::DOUBLE_QUOTED_LINE, $value, $matches) + ) { + $value = $matches[1]; + } + + if (preg_match(self::BOOLEAN, $value)) { + $value = (strtolower($value) === 'true'); + } elseif (preg_match(self::NUMBER, $value)) { + $value = intval($value); + } + + return new KeyValue($key, $value); + } +}
\ No newline at end of file diff --git a/src/Parser/ParserInterface.php b/src/Parser/ParserInterface.php index b53e29f..f67ffb5 100644 --- a/src/Parser/ParserInterface.php +++ b/src/Parser/ParserInterface.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -8,6 +10,10 @@ namespace NeonXP\Dotenv\Parser; use NeonXP\Dotenv\Types\KeyValue; +/** + * Interface ParserInterface + * @package NeonXP\Dotenv\Parser + */ interface ParserInterface { /** diff --git a/src/Types/KeyValue.php b/src/Types/KeyValue.php index e17dc4d..54b0360 100644 --- a/src/Types/KeyValue.php +++ b/src/Types/KeyValue.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * @author: Alexander Kiryukhin <alexander@kiryukhin.su> * @license: MIT @@ -6,7 +8,10 @@ namespace NeonXP\Dotenv\Types; - +/** + * Class KeyValue + * @package NeonXP\Dotenv\Types + */ class KeyValue { /** @@ -24,7 +29,7 @@ class KeyValue * @param string $key * @param mixed $value */ - public function __construct(string $key, mixed $value) + public function __construct(string $key, $value) { $this->key = $key; $this->value = $value; @@ -41,7 +46,7 @@ class KeyValue /** * @return mixed */ - public function getValue(): mixed + public function getValue() { return $this->value; } |