You've already forked config
Herping the derp
This commit is contained in:
324
src/Config.php
Normal file
324
src/Config.php
Normal file
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
namespace Siteworx\Config;
|
||||
|
||||
use Siteworx\Config\Exception\EmptyDirectoryException;
|
||||
use Siteworx\Config\Exception\FileNotFoundException;
|
||||
use Siteworx\Config\Exception\UnsupportedFormatException;
|
||||
use Siteworx\Config\Parser\Ini;
|
||||
use Siteworx\Config\Parser\Json;
|
||||
use Siteworx\Config\Parser\ParserInterface;
|
||||
use Siteworx\Config\Parser\Php;
|
||||
use Siteworx\Config\Parser\Properties;
|
||||
use Siteworx\Config\Parser\Serialize;
|
||||
use Siteworx\Config\Parser\Xml;
|
||||
use Siteworx\Config\Parser\Yaml;
|
||||
use Siteworx\Config\Writer\WriterInterface;
|
||||
|
||||
/**
|
||||
* Configuration reader and writer for PHP.
|
||||
*
|
||||
* @package Config
|
||||
* @author Jesus A. Domingo <jesus.domingo@gmail.com>
|
||||
* @author Hassan Khan <contact@hassankhan.me>
|
||||
* @author Filip Š <projects@filips.si>
|
||||
* @link https://github.com/noodlehaus/config
|
||||
* @license MIT
|
||||
*/
|
||||
class Config extends AbstractConfig
|
||||
{
|
||||
|
||||
/**
|
||||
* All formats supported by Config.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $supportedParsers = [
|
||||
Php::class,
|
||||
Ini::class,
|
||||
Json::class,
|
||||
Xml::class,
|
||||
Yaml::class,
|
||||
Properties::class,
|
||||
Serialize::class
|
||||
];
|
||||
|
||||
/**
|
||||
* All formats supported by Config.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $supportedWriters = [
|
||||
Writer\Ini::class,
|
||||
Writer\Json::class,
|
||||
Writer\Xml::class,
|
||||
Writer\Yaml::class,
|
||||
Writer\Properties::class,
|
||||
Writer\Serialize::class
|
||||
];
|
||||
|
||||
/**
|
||||
* Static method for loading a Config instance.
|
||||
*
|
||||
* @param string|array $paths Filenames or string with configuration
|
||||
* @param ParserInterface|null $parser Configuration parser
|
||||
* @param bool $loadFromString
|
||||
* @return Config
|
||||
* @throws EmptyDirectoryException
|
||||
* @throws FileNotFoundException
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
public static function load(
|
||||
string | array $paths,
|
||||
?ParserInterface $parser = null,
|
||||
bool $loadFromString = false
|
||||
): Config {
|
||||
return new static($paths, $parser, $loadFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Config instance.
|
||||
*
|
||||
* @param string|array $values Filenames or string with configuration
|
||||
* @param ParserInterface | null $parser Configuration parser
|
||||
* @throws EmptyDirectoryException
|
||||
* @throws FileNotFoundException
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
private function __construct(string | array $values, ParserInterface $parser = null, bool $loadFromString = false)
|
||||
{
|
||||
if ($loadFromString && !is_array($values) && !file_exists($values)) {
|
||||
if ($parser === null) {
|
||||
throw new \InvalidArgumentException('Parser is required to be provided for a string');
|
||||
}
|
||||
|
||||
$this->loadFromString($values, $parser);
|
||||
} else {
|
||||
$this->loadFromFile($values, $parser);
|
||||
}
|
||||
|
||||
parent::__construct($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration from file.
|
||||
*
|
||||
* @param string|array $path Filenames or directories with configuration
|
||||
* @param ParserInterface | null $parser Configuration parser
|
||||
*
|
||||
* @throws EmptyDirectoryException If `$path` is an empty directory
|
||||
* @throws FileNotFoundException
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
protected function loadFromFile(string | array $path, ?ParserInterface $parser = null): void
|
||||
{
|
||||
$paths = $this->getValidPaths($path);
|
||||
$this->data = [];
|
||||
|
||||
foreach ($paths as $filePath) {
|
||||
if ($parser === null) {
|
||||
// Get file information
|
||||
$info = pathinfo($filePath);
|
||||
$parts = explode('.', $info['basename']);
|
||||
$extension = array_pop($parts);
|
||||
|
||||
// Skip the `dist` extension
|
||||
if ($extension === 'dist') {
|
||||
$extension = array_pop($parts);
|
||||
}
|
||||
|
||||
// Get file parser
|
||||
$parser = $this->getParser($extension);
|
||||
|
||||
// Try to load file
|
||||
$newData = $parser->parseFile($filePath);
|
||||
$oldData = $this->data;
|
||||
|
||||
$this->data = array_merge($oldData, $newData);
|
||||
|
||||
// Clean parser
|
||||
$parser = null;
|
||||
} else {
|
||||
$newData = $parser->parseFile($filePath);
|
||||
$oldData = $this->data;
|
||||
|
||||
$this->data = array_merge($oldData, $newData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes configuration to file.
|
||||
*
|
||||
* @param string $filename Filename to save configuration to
|
||||
* @param WriterInterface|null $writer Configuration writer
|
||||
*
|
||||
* @throws Exception\WriteException if the data could not be written to the file
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
public function toFile(string $filename, WriterInterface $writer = null): void
|
||||
{
|
||||
if ($writer === null) {
|
||||
// Get file information
|
||||
$info = pathinfo($filename);
|
||||
$parts = explode('.', $info['basename']);
|
||||
$extension = array_pop($parts);
|
||||
|
||||
// Skip the `dist` extension
|
||||
if ($extension === 'dist') {
|
||||
$extension = array_pop($parts);
|
||||
}
|
||||
|
||||
// Get file writer
|
||||
$writer = $this->getWriter($extension);
|
||||
|
||||
// Try to save file
|
||||
$writer->toFile($this->all(), $filename);
|
||||
|
||||
// Clean writer
|
||||
$writer = null;
|
||||
} else {
|
||||
// Try to load file using specified writer
|
||||
$writer->toFile($this->all(), $filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration from string.
|
||||
*
|
||||
* @param string $configuration String with configuration
|
||||
* @param ParserInterface $parser Configuration parser
|
||||
*/
|
||||
protected function loadFromString(string $configuration, ParserInterface $parser): void
|
||||
{
|
||||
$this->data = [];
|
||||
|
||||
// Try to parse string
|
||||
$this->data = array_replace_recursive($this->data, $parser->parseString($configuration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes configuration to string.
|
||||
*
|
||||
* @param WriterInterface $writer Configuration writer
|
||||
* @param boolean $pretty Encode pretty
|
||||
*/
|
||||
public function toString(WriterInterface $writer, bool $pretty = true): string
|
||||
{
|
||||
return $writer->toString($this->all(), $pretty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parser for a given file extension.
|
||||
*
|
||||
* @throws UnsupportedFormatException If `$extension` is an unsupported file format
|
||||
*/
|
||||
protected function getParser(string $extension): ParserInterface
|
||||
{
|
||||
foreach ($this->supportedParsers as $parser) {
|
||||
if (in_array($extension, $parser::getSupportedExtensions(), true)) {
|
||||
return new $parser();
|
||||
}
|
||||
}
|
||||
|
||||
// If none exist, then throw an exception
|
||||
throw new UnsupportedFormatException('Unsupported configuration format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a writer for a given file extension.
|
||||
*
|
||||
* @throws UnsupportedFormatException If `$extension` is an unsupported file format
|
||||
*/
|
||||
protected function getWriter(string $extension): WriterInterface
|
||||
{
|
||||
foreach ($this->supportedWriters as $writer) {
|
||||
if (in_array($extension, $writer::getSupportedExtensions(), true)) {
|
||||
return new $writer();
|
||||
}
|
||||
}
|
||||
|
||||
// If none exist, then throw an exception
|
||||
throw new UnsupportedFormatException('Unsupported configuration format' . $extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of paths
|
||||
*
|
||||
* @param array $path
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws FileNotFoundException|EmptyDirectoryException If a file is not found at `$path`
|
||||
*/
|
||||
protected function getPathsFromArray(array $path): array
|
||||
{
|
||||
$paths = [];
|
||||
|
||||
foreach ($path as $unverifiedPath) {
|
||||
try {
|
||||
// Check if `$unverifiedPath` is optional
|
||||
// If it exists, then it's added to the list
|
||||
// If it doesn't, it throws an exception which we catch
|
||||
if ($unverifiedPath[0] !== '?') {
|
||||
$validPaths = $this->getValidPaths($unverifiedPath);
|
||||
$originalPaths = $paths;
|
||||
$paths = array_merge($originalPaths, $validPaths);
|
||||
continue;
|
||||
}
|
||||
|
||||
$optionalPath = ltrim($unverifiedPath, '?');
|
||||
|
||||
$validPaths = $this->getValidPaths($optionalPath);
|
||||
$originalPaths = $paths;
|
||||
|
||||
$paths = array_merge($originalPaths, $validPaths);
|
||||
} catch (FileNotFoundException $e) {
|
||||
// If `$unverifiedPath` is optional, then skip it
|
||||
if ($unverifiedPath[0] === '?') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, rethrow the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks `$path` to see if it is either an array, a directory, or a file.
|
||||
*
|
||||
* @param string|array $path
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws EmptyDirectoryException If `$path` is an empty directory
|
||||
*
|
||||
* @throws FileNotFoundException If a file is not found at `$path`
|
||||
*/
|
||||
protected function getValidPaths(string | array $path): array
|
||||
{
|
||||
if (is_array($path)) {
|
||||
return $this->getPathsFromArray($path);
|
||||
}
|
||||
|
||||
// If `$path` is a directory
|
||||
if (is_dir($path)) {
|
||||
$paths = glob($path . '/*.*');
|
||||
if (empty($paths)) {
|
||||
throw new EmptyDirectoryException("Configuration directory: [$path] is empty");
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
// If `$path` is not a file, throw an exception
|
||||
if (!file_exists($path)) {
|
||||
throw new FileNotFoundException("Configuration file: [$path] cannot be found");
|
||||
}
|
||||
|
||||
return [$path];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user