Added loaders

This commit is contained in:
R. Eric Wheeler 2017-11-07 13:30:35 -08:00
parent 4b81fc105e
commit a9e7b22989
14 changed files with 508 additions and 21 deletions

View File

@ -4,29 +4,37 @@
"type": "project",
"require": {
"php": ">=7.1",
"dflydev/dot-access-data": "1.1",
"symfony/filesystem": "^3.3",
"symfony/yaml": "^3.3"
"dflydev/dot-access-data": "^1.1",
"symfony/filesystem": "^3.3"
},
"autoload": {
"psr-4": {
"Sikofitt\\Configuration\\": "src/Sikofitt/Configuration"
"Sikofitt\\Config\\": "src/Sikofitt/Config"
}
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.6",
"nette/neon": "^2.4",
"phpro/grumphp": "^0.12.0",
"phpstan/phpstan": "^0.8.5",
"phpunit/phpunit": "~5.7|~6.3",
"sensiolabs/security-checker": "^4.1",
"squizlabs/php_codesniffer": "^3.1",
"symfony/var-dumper": "^3.3"
"symfony/var-dumper": "^3.3",
"symfony/yaml": "^3.3",
"webmozart/json": "^1.2"
},
"autoload-dev": {
"psr-4": {
"Sikofitt\\Tests\\": "tests/Sikofitt/Tests"
}
},
"suggest": {
"webmozart/json": "For using the webmozart json parser. Instead of the default php one.",
"nette/neon": "For parsing .neon files.",
"symfony/yaml": "For parsing yaml files."
},
"license": "GPL-3.0",
"authors": [
{

View File

@ -29,10 +29,10 @@ parameters:
phpversion:
project: '7.1'
phpcs:
standard: PSR2
standard: 'phpcs.xml.dist'
show_warnings: true
encoding: UTF8
triggered_by: [php]
triggered_by: ['php']
securitychecker:
run_always: false
xmllint:

View File

@ -20,7 +20,15 @@
namespace Sikofitt\Config;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Config\FileLocatorInterface;
use Sikofitt\Config\Loader\IniFileLoader;
use Sikofitt\Config\Loader\JsonFileLoader;
use Sikofitt\Config\Loader\NeonFileLoader;
use Sikofitt\Config\Loader\PhpFileLoader;
use Sikofitt\Config\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\GlobFileLoader;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\Yaml\Yaml;
@ -33,26 +41,60 @@ class DotConfig
{
private $config;
private $arrayConfig;
private $delegateLoader;
/**
* Configuration constructor.
*
* @param \Symfony\Component\Config\FileLocatorInterface $fileLocator
* @param string $configDirectory
* @param string|array $configResource
*
* @throws \InvalidArgumentException
* @throws \Symfony\Component\Yaml\Exception\ParseException
* @throws \Symfony\Component\Config\Exception\FileLocatorFileNotFoundException
* @throws \Exception
*/
public function __construct(
FileLocatorInterface $fileLocator,
string $configDirectory
$configResource
) {
$file = $fileLocator->locate('config.yaml', $configDirectory);
$contents = file_get_contents($file);
$data = Yaml::parse($contents);
$this->arrayConfig = $data;
$this->config = new Data($data);
$this->arrayConfig = [];
$locator = new FileLocator();
$loaderResolver = new LoaderResolver();
$loaderResolver->addLoader(new PhpFileLoader($locator));
$loaderResolver->addLoader(new JsonFileLoader($locator));
$loaderResolver->addLoader(new IniFileLoader($locator));
$loaderResolver->addLoader(new GlobFileLoader($locator));
if (class_exists('Symfony\Component\Yaml\Yaml')) {
$loaderResolver->addLoader(new YamlFileLoader($locator));
}
if (class_exists('Nette\Neon\Neon')) {
$loaderResolver->addLoader(new NeonFileLoader($locator));
}
$this->delegateLoader = new DelegatingLoader($loaderResolver);
if (is_array($configResource)) {
$configResource = $this->loadDirectories($configResource);
$configResource = $this->loadFiles($configResource);
$configResource = array_shift($configResource);
if (!empty($configResource)) {
$this->arrayConfig = array_merge_recursive(
$configResource,
$this->arrayConfig
);
}
} else {
if (is_file($configResource)) {
$this->arrayConfig = $this->delegateLoader->load($configResource);
}
}
$this->config = new Data($this->arrayConfig);
}
public function getArrayConfig(): array
{
return $this->arrayConfig;
}
/**
@ -70,7 +112,7 @@ class DotConfig
$data[$key] = (array)$value;
}
}
$data = Yaml::dump($data, 4, 4, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
return (bool)file_put_contents($fileName, $data);
}
@ -245,4 +287,54 @@ class DotConfig
{
return $this->config->has($key);
}
/**
* @param array $directories
*
* @throws \Exception
* @return array
*/
private function loadDirectories(array $directories): array
{
foreach ($directories as $key => $config) {
if (is_string($config) && is_dir($config)) {
$this->arrayConfig = array_merge_recursive(
$this->arrayConfig,
$this->delegateLoader->load($config . '/**', 'glob')
);
unset($directories[$key]);
$this->arrayConfig = $this->mergeGlob($this->arrayConfig);
}
}
return $directories;
}
/**
* @param array $files
*
* @throws \Exception
* @return array
*/
private function loadFiles(array $files): array
{
foreach ($files as $key => $config) {
if (is_string($config) && is_file($config)) {
$this->arrayConfig = array_merge_recursive($this->arrayConfig, $this->delegateLoader->load($config));
unset($files[$key]);
}
}
return $files;
}
private function mergeGlob(array $globResource): array
{
$result = [];
foreach ($globResource as $glob) {
$result = array_merge_recursive($result, $glob);
}
return $result;
}
}

View File

@ -0,0 +1,46 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader\Exception;
use Throwable;
/**
* An Error Exception.
*
* @link http://php.net/manual/en/class.errorexception.php
*/
class JsonDecodingException extends \ErrorException
{
public function __construct(
$severity = E_RECOVERABLE_ERROR,
$fileName = __FILE__,
$line = __LINE__,
Throwable $previous
) {
parent::__construct(
json_last_error_msg(),
json_last_error(),
$severity,
$fileName,
$line,
$previous
);
}
}

View File

@ -0,0 +1,57 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader;
use Symfony\Component\Config\Loader\FileLoader;
class IniFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
* @return array|bool
*
*/
public function load($resource, $type = null)
{
$data = parse_ini_file($resource, true);
return false === $data ? [] : $data;
}
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return
$type === 'ini' ||
pathinfo($resource, PATHINFO_EXTENSION) === 'ini';
}
}

View File

@ -0,0 +1,62 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader;
use Symfony\Component\Config\Loader\FileLoader;
use Webmozart\Json\JsonDecoder;
class JsonFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
* @return mixed
*
*/
public function load($resource, $type = null)
{
if (class_exists('Webmozart\Json\JsonDecoder')) {
$decoder = new JsonDecoder();
return (array)$decoder->decodeFile($resource);
}
return \json_decode(file_get_contents($resource), true);
}
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null): bool
{
return
$type === 'json' ||
pathinfo($resource, PATHINFO_EXTENSION) === 'json';
}
}

View File

@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader;
use Nette\Neon\Neon;
use Symfony\Component\Config\Loader\FileLoader;
class NeonFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
* @return mixed
*
*/
public function load($resource, $type = null)
{
return Neon::decode(file_get_contents($resource));
}
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return
$type === 'neon' ||
pathinfo($resource, PATHINFO_EXTENSION) === 'neon';
}
}

View File

@ -0,0 +1,60 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader;
use Symfony\Component\Config\Loader\FileLoader;
class PhpFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
* @return array
*
*/
public function load($resource, $type = null): array
{
return
require $resource;
}
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null): bool
{
return
$type === 'php' ||
in_array(
pathinfo($resource, PATHINFO_EXTENSION),
['php', 'inc'],
true
);
}
}

View File

@ -0,0 +1,55 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Sikofitt\Config\Loader;
use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Yaml\Yaml;
class YamlFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
* @return mixed
*/
public function load($resource, $type = null)
{
return Yaml::parse(file_get_contents($resource));
}
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return
is_string($resource) &&
in_array(pathinfo($resource, PATHINFO_EXTENSION), ['yaml', 'yml'], true);
}
}

4
tests/fixtures/config.ini vendored Normal file
View File

@ -0,0 +1,4 @@
[config]
value = ini
ini_test[] = testing1
ini_test[] = testing2

9
tests/fixtures/config.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"config": {
"value": "json",
"json_test": [
"testing1",
"testing2"
]
}
}

5
tests/fixtures/config.neon vendored Normal file
View File

@ -0,0 +1,5 @@
config:
value: neon
neon_test:
- testing1
- testing2

28
tests/fixtures/config.php vendored Normal file
View File

@ -0,0 +1,28 @@
<?php declare(strict_types=1);
/*
* Copyleft (C) 2017 http://sikofitt.com sikofitt@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
return [
'config' => [
'value' => 'php',
'php_test' => [
'testing1',
'testing2',
],
],
];

5
tests/fixtures/config.yaml vendored Normal file
View File

@ -0,0 +1,5 @@
config:
value: 'yaml'
yaml_test:
- testing
- testing1