Skip to content

[4.1] Refactor to use stores #395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Upgrading Guide

## V4.0 to V4.1

There are no breaking changes in this release, but the `Dotenv\Dotenv` constructor now expects either an array of file paths as the third parameter, or an instance of `Dotenv\Store\StoreInterface`. Passing an array is deprecated, and will be removed in V5.

## V3 to V4

V4 has again changed the way you initialize the `Dotenv` class. If you want immutable loading of environment variables, then replace `Dotenv::create` with `Dotenv::createImmutable`, and if you want mutable loading, replace `Dotenv::create` with `Dotenv::createMutable` and `->overload()` with `->load()`. The `overload` method has been removed in faviour of specifying mutability at object construction.
Expand Down
82 changes: 20 additions & 62 deletions src/Dotenv.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
namespace Dotenv;

use Dotenv\Exception\InvalidPathException;
use Dotenv\File\Paths;
use Dotenv\File\Reader;
use Dotenv\Loader\Loader;
use Dotenv\Loader\LoaderInterface;
use Dotenv\Repository\RepositoryBuilder;
use Dotenv\Repository\RepositoryInterface;
use PhpOption\Option;
use Dotenv\Store\StoreBuilder;

class Dotenv
{
Expand All @@ -28,35 +26,26 @@ class Dotenv
protected $repository;

/**
* The file paths.
* The store instance.
*
* @var string[]
* @var \Dotenv\Store\StoreInterface
*/
protected $filePaths;

/**
* Should file loading short circuit?
*
* @var bool
*/
protected $shortCircuit;
protected $store;

/**
* Create a new dotenv instance.
*
* @param \Dotenv\Loader\LoaderInterface $loader
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string[] $filePaths
* @param bool $shortCircuit
* @param \Dotenv\Store\StoreInterface|string[] $store
*
* @return void
*/
public function __construct(LoaderInterface $loader, RepositoryInterface $repository, array $filePaths, $shortCircuit = true)
public function __construct(LoaderInterface $loader, RepositoryInterface $repository, $store)
{
$this->loader = $loader;
$this->repository = $repository;
$this->filePaths = $filePaths;
$this->shortCircuit = $shortCircuit;
$this->store = is_array($store) ? new Store($store, true) : $store;
}

/**
Expand All @@ -71,9 +60,13 @@ public function __construct(LoaderInterface $loader, RepositoryInterface $reposi
*/
public static function create(RepositoryInterface $repository, $paths, $names = null, $shortCircuit = true)
{
$files = Paths::filePaths((array) $paths, (array) ($names ?: '.env'));
$builder = StoreBuilder::create()->withPaths((array) $paths)->withNames((array) ($names ?: '.env'));

if ($shortCircuit) {
$builder = $builder->shortCircuit();
}

return new self(new Loader(), $repository, $files, $shortCircuit);
return new self(new Loader(), $repository, $builder->make());
}

/**
Expand Down Expand Up @@ -117,15 +110,7 @@ public static function createImmutable($paths, $names = null, $shortCircuit = tr
*/
public function load()
{
if ($this->filePaths === []) {
throw new InvalidPathException('At least one environment file path must be provided.');
}

return $this->tryLoad()->getOrCall(function () {
throw new InvalidPathException(
sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $this->filePaths))
);
});
return $this->loader->load($this->repository, $this->store->read());
}

/**
Expand All @@ -137,7 +122,12 @@ public function load()
*/
public function safeLoad()
{
return $this->tryLoad()->getOrElse([]);
try {
return $this->load();
} catch (InvalidPathException $e) {
// suppressing exception
return [];
}
}

/**
Expand All @@ -163,36 +153,4 @@ public function ifPresent($variables)
{
return new Validator($this->repository, (array) $variables, false);
}

/**
* Read and load environment file(s), returning an option.
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return \PhpOption\Option
*/
private function tryLoad()
{
return self::aggregate(Reader::read($this->filePaths, $this->shortCircuit))->map(function ($content) {
return $this->loader->load($this->repository, $content);
});
}

/**
* Aggregate the given raw file contents.
*
* @param array<string,string> $contents
*
* @return \PhpOption\Option
*/
private static function aggregate(array $contents)
{
$output = '';

foreach ($contents as $content) {
$output .= $content."\n";
}

return Option::fromValue($output, '');
}
}
4 changes: 1 addition & 3 deletions src/File/Paths.php → src/Store/File/Paths.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php

namespace Dotenv\File;

use PhpOption\Option;
namespace Dotenv\Store\File;

class Paths
{
Expand Down
2 changes: 1 addition & 1 deletion src/File/Reader.php → src/Store/File/Reader.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Dotenv\File;
namespace Dotenv\Store\File;

use PhpOption\Option;

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

namespace Dotenv\Store;

use Dotenv\Exception\InvalidPathException;
use Dotenv\Store\File\Reader;

class FileStore implements StoreInterface
{
/**
* The file paths.
*
* @var string[]
*/
protected $filePaths;

/**
* Should file loading short circuit?
*
* @var bool
*/
protected $shortCircuit;

/**
* Create a new file store instance.
*
* @param string[] $filePaths
* @param bool $shortCircuit
*
* @return void
*/
public function __construct(array $filePaths, $shortCircuit)
{
$this->filePaths = $filePaths;
$this->shortCircuit = $shortCircuit;
}

/**
* Read the content of the environment file(s).
*
* @throws \Dotenv\Exception\InvalidPathException
*
* @return string
*/
public function read()
{
if ($this->filePaths === []) {
throw new InvalidPathException('At least one environment file path must be provided.');
}

$contents = Reader::read($this->filePaths, $this->shortCircuit);

if ($contents) {
return implode("\n", $contents);
}

throw new InvalidPathException(
sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $this->filePaths))
);
}
}
102 changes: 102 additions & 0 deletions src/Store/StoreBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace Dotenv\Store;

use Dotenv\Store\File\Paths;

class StoreBuilder
{
/**
* The paths to search within.
*
* @var string[]
*/
private $paths;

/**
* The file names to search for.
*
* @var string[]
*/
private $names;

/**
* Should file loading short circuit?
*
* @var bool
*/
protected $shortCircuit;

/**
* Create a new store builder instance.
*
* @param string[] $paths
* @param string[] $names
* @param bool $shortCircuit
*
* @return void
*/
private function __construct(array $paths = [], array $names = [], $shortCircuit = false)
{
$this->paths = $paths;
$this->names = $names;
$this->shortCircuit = $shortCircuit;
}

/**
* Create a new store builder instance.
*
* @return \Dotenv\Store\StoreBuilder
*/
public static function create()
{
return new self();
}

/**
* Creates a store builder with the given paths.
*
* @param string[] $paths
*
* @return \Dotenv\Repository\RepositoryBuilder
*/
public function withPaths(array $paths)
{
return new self($paths, $this->names, $this->shortCircuit);
}

/**
* Creates a store builder with the given names.
*
* @param string[] $names
*
* @return \Dotenv\Store\StoreBuilder
*/
public function withNames(array $names)
{
return new self($this->paths, $names, $this->shortCircuit);
}

/**
* Creates a store builder with short circuit mode enabled.
*
* @return \Dotenv\Store\StoreBuilder
*/
public function shortCircuit()
{
return new self($this->paths, $this->names, true);
}

/**
* Creates a new store instance.
*
* @return \Dotenv\Store\StoreInterface
*/
public function make()
{
return new FileStore(
Paths::filePaths($this->paths, $this->names),
$this->shortCircuit
);
}
}
15 changes: 15 additions & 0 deletions src/Store/StoreInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Dotenv\Store;

interface StoreInterface
{
/**
* Read the content of the environment file(s).
*
* @throws \Dotenv\Exception\InvalidPathException
*
* @return string
*/
public function read();
}
Loading