diff --git a/README.md b/README.md index f295d41..41f2a16 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ use DevCoder\DotEnv; echo getenv('APP_ENV'); // dev -echo getenv('DATABASE_DNS') +echo getenv('DATABASE_DNS'); // mysql:host=localhost;dbname=test; ``` Ideal for small project diff --git a/src/DotEnv.php b/src/DotEnv.php index 39f9a48..8fae94c 100644 --- a/src/DotEnv.php +++ b/src/DotEnv.php @@ -4,6 +4,19 @@ class DotEnv { + /** + * Convert true and false to booleans, instead of: + * + * VARIABLE=false -> ['VARIABLE' => 'false'] + * + * it will be + * + * VARIABLE=false -> ['VARIABLE' => false] + * + * default = true + */ + const PROCESS_BOOLEANS = 'PROCESS_BOOLEANS'; + /** * The directory where the .env file can be located. * @@ -11,15 +24,36 @@ class DotEnv */ protected $path; - public function __construct(string $path) + /** + * Configure the options on which the parsed will act + * + * @var array + */ + protected $options = []; + + public function __construct(string $path, array $options = []) { - if(!file_exists($path)) { + if (!file_exists($path)) { throw new \InvalidArgumentException(sprintf('%s does not exist', $path)); } + $this->path = $path; + + $this->processOptions($options); } - public function load() :void + private function processOptions(array $options) : void + { + $this->options = array_merge([ + static::PROCESS_BOOLEANS => true + ], $options); + } + + /** + * Processes the $path of the instances and parses the values into $_SERVER and $_ENV, also returns all the data that has been read. + * Skips empty and commented lines. + */ + public function load() : void { if (!is_readable($this->path)) { throw new \RuntimeException(sprintf('%s file is not readable', $this->path)); @@ -34,7 +68,7 @@ public function load() :void list($name, $value) = explode('=', $line, 2); $name = trim($name); - $value = trim($value); + $value = $this->processValue($value); if (!array_key_exists($name, $_SERVER) && !array_key_exists($name, $_ENV)) { putenv(sprintf('%s=%s', $name, $value)); @@ -43,4 +77,20 @@ public function load() :void } } } + + private function processValue(string $value) { + $trimmedValue = trim($value); + + if (!empty($this->options[static::PROCESS_BOOLEANS])) { + $loweredValue = strtolower($trimmedValue); + + $isBoolean = in_array($loweredValue, ['true', 'false'], true); + + if ($isBoolean) { + return $loweredValue === 'true'; + } + } + + return $trimmedValue; + } } diff --git a/tests/DotenvTest.php b/tests/DotenvTest.php index 62e3698..b8f7bc8 100644 --- a/tests/DotenvTest.php +++ b/tests/DotenvTest.php @@ -2,15 +2,21 @@ namespace Test\DevCoder; - use DevCoder\DotEnv; use PHPUnit\Framework\TestCase; class DotenvTest extends TestCase { + private function env(string $file) + { + return __DIR__ . DIRECTORY_SEPARATOR . 'env' . DIRECTORY_SEPARATOR . $file; + } + /** + * @runInSeparateProcess + */ public function testLoad() { - (new DotEnv(__DIR__ . '/.env'))->load(); + (new DotEnv($this->env('.env.default')))->load(); $this->assertEquals('dev', getenv('APP_ENV')); $this->assertEquals('mysql:host=localhost;dbname=test;', getenv('DATABASE_DNS')); $this->assertEquals('root', getenv('DATABASE_USER')); @@ -35,6 +41,53 @@ public function testLoad() { public function testFileNotExist() { $this->expectException(\InvalidArgumentException::class); - (new DotEnv(__DIR__ . '/.env.local'))->load(); + (new DotEnv($this->env('.env.not-exists')))->load(); + } + + /** + * @runInSeparateProcess + */ + public function testLoadReturnsValues() + { + $loaded = (new DotEnv($this->env('.env.return')))->load(); + + $this->assertEquals('returned', $loaded['VALUE']); + $this->assertEquals('returned', $_ENV['VALUE']); + } + + /** + * @runInSeparateProcess + */ + public function testProcessBoolean() + { + (new DotEnv($this->env('.env.boolean'), [ + DotEnv::PROCESS_BOOLEANS => true + ]))->load(); + + $this->assertEquals(false, $_ENV['FALSE1']); + $this->assertEquals(false, $_ENV['FALSE2']); + $this->assertEquals(false, $_ENV['FALSE3']); + $this->assertEquals("'false'", $_ENV['FALSE4']); + $this->assertEquals('0', $_ENV['FALSE5']); + + $this->assertEquals(true, $_ENV['TRUE1']); + $this->assertEquals(true, $_ENV['TRUE2']); + $this->assertEquals(true, $_ENV['TRUE3']); + $this->assertEquals("'true'", $_ENV['TRUE4']); + $this->assertEquals('1', $_ENV['TRUE5']); + } + + /** + * @runInSeparateProcess + */ + public function testDontProcessBoolean() + { + (new DotEnv($this->env('.env.boolean'), [ + DotEnv::PROCESS_BOOLEANS => false + ]))->load(); + + $this->assertEquals('false', $_ENV['FALSE1']); + + $this->assertEquals('true', $_ENV['TRUE1']); } } diff --git a/tests/env/.env.boolean b/tests/env/.env.boolean new file mode 100644 index 0000000..e30ad05 --- /dev/null +++ b/tests/env/.env.boolean @@ -0,0 +1,10 @@ +FALSE1=false +FALSE2= false +FALSE3=FALSE +FALSE4='false' +FALSE5=0 +TRUE1=true +TRUE2= true +TRUE3=TRUE +TRUE4='true' +TRUE5=1 \ No newline at end of file diff --git a/tests/.env b/tests/env/.env.default similarity index 100% rename from tests/.env rename to tests/env/.env.default diff --git a/tests/env/.env.return b/tests/env/.env.return new file mode 100644 index 0000000..8ba2093 --- /dev/null +++ b/tests/env/.env.return @@ -0,0 +1 @@ +VALUE=returned \ No newline at end of file