Skip to content
This repository has been archived by the owner on Mar 20, 2022. It is now read-only.

Commit

Permalink
Adding type casts into parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Dusan Malusev committed Nov 9, 2019
1 parent f1adfa6 commit 946b8cf
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 44 deletions.
25 changes: 15 additions & 10 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 40 additions & 13 deletions src/EnvParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,25 @@ class EnvParser implements Tokens, EnvParserInterface
*/
private $handler;

/**
* @var array<integer, string>
*/
private $typeCasters = [
];


/**
* @var ValueType
*/
private $typeChecker;

/**
* Holder for parsed Environment Variables
*
* @internal
* @var null|array
*/
private $envs = NULL;
private $envs;

/**
* Flag that doesn't allows the lexing and paring stages to happen twice
Expand All @@ -41,9 +53,11 @@ class EnvParser implements Tokens, EnvParserInterface
*
* @param string $file
*
* @throws Exception
* @param array $typeCasters
* @param ValueType|null $typeChecker
* @param bool $emptyStringNull
*/
public function __construct(string $file)
public function __construct(string $file, ?array $typeCasters = null, ValueType $typeChecker = null, bool $emptyStringNull = true)
{
$this->handler = new File($file);
if ($this->handler === NULL) {
Expand All @@ -55,6 +69,16 @@ public function __construct(string $file)
if (!$this->handler->isReadable()) {
throw new RuntimeException($file . ' is not readable');
}

if($typeCasters !== null) {
$this->typeCasters = array_merge($this->typeCasters, $typeCasters);
}
if($typeChecker === null)
{
$typeChecker = new TypeChecker($emptyStringNull);
}

$this->typeChecker = $typeChecker;
}


Expand Down Expand Up @@ -109,13 +133,14 @@ private function extractName(string $startingChar, int & $column): string
while (($c = $this->handler->fgetc()) === self::SPACE) {
continue;
}
if ($c === self::EQUALS) break;
else {
$error = new DotEnvSyntaxError('Spaces are now allowed in env variable name');
$error->setEnvLine($this->handler->key());
$error->setColumn($column);
throw $error;
if ($c === self::EQUALS) {
break;
}

$error = new DotEnvSyntaxError('Spaces are now allowed in env variable name');
$error->setEnvLine($this->handler->key());
$error->setColumn($column);
throw $error;
}
if ($c === self::CARRIAGE_RETURN || $c === self::NEW_LINE || $c === self::COMMENT) {
$error = new DotEnvSyntaxError('Unexpected end of line');
Expand All @@ -136,17 +161,18 @@ private function extractName(string $startingChar, int & $column): string
* @param bool $raw
* @param int $column
*
* @return string
* @return int|string|float|null
* @throws EnvVariableNotFound
*/
private function extractValue(array $envs, bool $raw, int & $column): string
private function extractValue(array $envs, bool $raw, int & $column)
{
$value = '';
// Trimming the leading spaces of the value
while (($c = $this->handler->fgetc()) === self::SPACE) {
$column++;
continue;
};
}

$this->handler->fseek($this->handler->ftell() - 1);

// Handling Multiline values
Expand Down Expand Up @@ -187,7 +213,8 @@ private function extractValue(array $envs, bool $raw, int & $column): string
}
$column++;
}
return $value;

return $this->typeChecker->detectValue($value);
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/Parser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php


namespace BrosSquad\DotEnv;


interface Parser
{
/**
* @param string $value
* @return mixed
*/
public function parse(string $value);
}
22 changes: 11 additions & 11 deletions src/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
*/
interface Tokens
{
const EQUALS = '=';
const COMMENT = '#';
const MULTI_LINE_START = '"';
const MULTI_LINE_STOP = '"';
const SPACE = ' ';
const NEW_LINE = "\n";
const TAB = "\t";
const CARRIAGE_RETURN = "\r";
public const EQUALS = '=';
public const COMMENT = '#';
public const MULTI_LINE_START = '"';
public const MULTI_LINE_STOP = '"';
public const SPACE = ' ';
public const NEW_LINE = "\n";
public const TAB = "\t";
public const CARRIAGE_RETURN = "\r";

const INTERPOLATION_INDICATOR = '$';
const INTERPOLATION_START = '{';
const INTERPOLATION_END = '}';
public const INTERPOLATION_INDICATOR = '$';
public const INTERPOLATION_START = '{';
public const INTERPOLATION_END = '}';
}
69 changes: 69 additions & 0 deletions src/TypeChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php


namespace BrosSquad\DotEnv;


class TypeChecker implements ValueType
{
private $emptyStringAsNull;

public function __construct(bool $emptyStringAsNull)
{
$this->emptyStringAsNull = $emptyStringAsNull;
}

public function detectValue(string $value)
{
$toLower = strtolower($value);

// Detecting NULL
if (strcmp('null', $toLower) === 0 || ($this->emptyStringAsNull === true && strcmp('', $toLower) === 0)) {
return null;
}

// Detecting BOOLEANS
if (($isBoolean = $this->checkForBoolean($toLower)) !== null) {
return (bool)$isBoolean;
}

// Detecting FLOATS
$trimmed = ltrim($toLower, '0');



$casted = (float)$toLower;

if (($casted !== 0.0 || strcmp('.0', $trimmed) === 0) && preg_match('/^\d+\.\d+$/', $toLower) === 1) {
return $casted;
}

// Detecting INTEGERS
$casted = (int)$trimmed;

if ($casted !== 0 || strcmp('', $trimmed) === 0) {
return $casted;
}

return $value;
}


private function checkForBoolean(string $value): ?int
{
switch ($value) {
case 'ok':
// case '1':
case 'true':
case 'yes':
case 'y':
return true;
case 'no':
// case '0':
case 'false':
return false;
default:
return null;
}
}
}
16 changes: 16 additions & 0 deletions src/ValueType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php


namespace BrosSquad\DotEnv;


interface ValueType
{
public const NULL = 0;
public const INTEGER = 1;
public const FLOAT = 2;
public const STRING = 'STRING';
public const BOOLEAN = 'BOOLEAN';

public function detectValue(string $value);
}
9 changes: 9 additions & 0 deletions tests/EnvTest/.env.casts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
INTEGERS=123
BOOLEAN=false
BOOLEAN_TRUE=true
NULLABLE=null
UPPERNULL = NULL
STR=SOME_STRING
FLOATS=1.65
FLOAT_ZERO=0.0
INT_ZERO=0
Loading

0 comments on commit 946b8cf

Please sign in to comment.