first commit
This commit is contained in:
255
vendor/league/config/src/Configuration.php
vendored
Normal file
255
vendor/league/config/src/Configuration.php
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
use Dflydev\DotAccessData\Data;
|
||||
use Dflydev\DotAccessData\DataInterface;
|
||||
use Dflydev\DotAccessData\Exception\DataException;
|
||||
use Dflydev\DotAccessData\Exception\InvalidPathException;
|
||||
use Dflydev\DotAccessData\Exception\MissingPathException;
|
||||
use League\Config\Exception\UnknownOptionException;
|
||||
use League\Config\Exception\ValidationException;
|
||||
use Nette\Schema\Expect;
|
||||
use Nette\Schema\Processor;
|
||||
use Nette\Schema\Schema;
|
||||
use Nette\Schema\ValidationException as NetteValidationException;
|
||||
|
||||
final class Configuration implements ConfigurationBuilderInterface, ConfigurationInterface
|
||||
{
|
||||
/** @psalm-readonly */
|
||||
private Data $userConfig;
|
||||
|
||||
/**
|
||||
* @var array<string, Schema>
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
private array $configSchemas = [];
|
||||
|
||||
/** @psalm-allow-private-mutation */
|
||||
private Data $finalConfig;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
private array $cache = [];
|
||||
|
||||
/** @psalm-readonly */
|
||||
private ConfigurationInterface $reader;
|
||||
|
||||
/**
|
||||
* @param array<string, Schema> $baseSchemas
|
||||
*/
|
||||
public function __construct(array $baseSchemas = [])
|
||||
{
|
||||
$this->configSchemas = $baseSchemas;
|
||||
$this->userConfig = new Data();
|
||||
$this->finalConfig = new Data();
|
||||
|
||||
$this->reader = new ReadOnlyConfiguration($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new configuration schema at the given top-level key
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
public function addSchema(string $key, Schema $schema): void
|
||||
{
|
||||
$this->invalidate();
|
||||
|
||||
$this->configSchemas[$key] = $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
public function merge(array $config = []): void
|
||||
{
|
||||
$this->invalidate();
|
||||
|
||||
$this->userConfig->import($config, DataInterface::REPLACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
public function set(string $key, $value): void
|
||||
{
|
||||
$this->invalidate();
|
||||
|
||||
try {
|
||||
$this->userConfig->set($key, $value);
|
||||
} catch (DataException $ex) {
|
||||
throw new UnknownOptionException($ex->getMessage(), $key, (int) $ex->getCode(), $ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-external-mutation-free
|
||||
*/
|
||||
public function get(string $key)
|
||||
{
|
||||
if (\array_key_exists($key, $this->cache)) {
|
||||
return $this->cache[$key];
|
||||
}
|
||||
|
||||
try {
|
||||
$this->build(self::getTopLevelKey($key));
|
||||
|
||||
return $this->cache[$key] = $this->finalConfig->get($key);
|
||||
} catch (InvalidPathException | MissingPathException $ex) {
|
||||
throw new UnknownOptionException($ex->getMessage(), $key, (int) $ex->getCode(), $ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-external-mutation-free
|
||||
*/
|
||||
public function exists(string $key): bool
|
||||
{
|
||||
if (\array_key_exists($key, $this->cache)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->build(self::getTopLevelKey($key));
|
||||
|
||||
return $this->finalConfig->has($key);
|
||||
} catch (InvalidPathException | UnknownOptionException $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-mutation-free
|
||||
*/
|
||||
public function reader(): ConfigurationInterface
|
||||
{
|
||||
return $this->reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-external-mutation-free
|
||||
*/
|
||||
private function invalidate(): void
|
||||
{
|
||||
$this->cache = [];
|
||||
$this->finalConfig = new Data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the schema against the configuration to return the final configuration
|
||||
*
|
||||
* @throws ValidationException|UnknownOptionException|InvalidPathException
|
||||
*
|
||||
* @psalm-allow-private-mutation
|
||||
*/
|
||||
private function build(string $topLevelKey): void
|
||||
{
|
||||
if ($this->finalConfig->has($topLevelKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! isset($this->configSchemas[$topLevelKey])) {
|
||||
throw new UnknownOptionException(\sprintf('Missing config schema for "%s"', $topLevelKey), $topLevelKey);
|
||||
}
|
||||
|
||||
try {
|
||||
$userData = [$topLevelKey => $this->userConfig->get($topLevelKey)];
|
||||
} catch (DataException $ex) {
|
||||
$userData = [];
|
||||
}
|
||||
|
||||
try {
|
||||
$schema = $this->configSchemas[$topLevelKey];
|
||||
$processor = new Processor();
|
||||
|
||||
$processed = $processor->process(Expect::structure([$topLevelKey => $schema]), $userData);
|
||||
|
||||
$this->raiseAnyDeprecationNotices($processor->getWarnings());
|
||||
|
||||
$this->finalConfig->import((array) self::convertStdClassesToArrays($processed));
|
||||
} catch (NetteValidationException $ex) {
|
||||
throw new ValidationException($ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively converts stdClass instances to arrays
|
||||
*
|
||||
* @phpstan-template T
|
||||
*
|
||||
* @param T $data
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @phpstan-return ($data is \stdClass ? array<string, mixed> : T)
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function convertStdClassesToArrays($data)
|
||||
{
|
||||
if ($data instanceof \stdClass) {
|
||||
$data = (array) $data;
|
||||
}
|
||||
|
||||
if (\is_array($data)) {
|
||||
foreach ($data as $k => $v) {
|
||||
$data[$k] = self::convertStdClassesToArrays($v);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $warnings
|
||||
*/
|
||||
private function raiseAnyDeprecationNotices(array $warnings): void
|
||||
{
|
||||
foreach ($warnings as $warning) {
|
||||
@\trigger_error($warning, \E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPathException
|
||||
*/
|
||||
private static function getTopLevelKey(string $path): string
|
||||
{
|
||||
if (\strlen($path) === 0) {
|
||||
throw new InvalidPathException('Path cannot be an empty string');
|
||||
}
|
||||
|
||||
$path = \str_replace(['.', '/'], '.', $path);
|
||||
|
||||
$firstDelimiter = \strpos($path, '.');
|
||||
if ($firstDelimiter === false) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return \substr($path, 0, $firstDelimiter);
|
||||
}
|
||||
}
|
22
vendor/league/config/src/ConfigurationAwareInterface.php
vendored
Normal file
22
vendor/league/config/src/ConfigurationAwareInterface.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
/**
|
||||
* Implement this class to facilitate setter injection of the configuration where needed
|
||||
*/
|
||||
interface ConfigurationAwareInterface
|
||||
{
|
||||
public function setConfiguration(ConfigurationInterface $configuration): void;
|
||||
}
|
21
vendor/league/config/src/ConfigurationBuilderInterface.php
vendored
Normal file
21
vendor/league/config/src/ConfigurationBuilderInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
/**
|
||||
* An interface that provides the ability to set both the schema and configuration values
|
||||
*/
|
||||
interface ConfigurationBuilderInterface extends MutableConfigurationInterface, SchemaBuilderInterface
|
||||
{
|
||||
}
|
46
vendor/league/config/src/ConfigurationInterface.php
vendored
Normal file
46
vendor/league/config/src/ConfigurationInterface.php
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
use League\Config\Exception\UnknownOptionException;
|
||||
use League\Config\Exception\ValidationException;
|
||||
|
||||
/**
|
||||
* Interface for reading configuration values
|
||||
*/
|
||||
interface ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* @param string $key Configuration option path/key
|
||||
*
|
||||
* @psalm-param non-empty-string $key
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ValidationException if the schema failed to validate the given input
|
||||
* @throws UnknownOptionException if the requested key does not exist or is malformed
|
||||
*/
|
||||
public function get(string $key);
|
||||
|
||||
/**
|
||||
* @param string $key Configuration option path/key
|
||||
*
|
||||
* @psalm-param non-empty-string $key
|
||||
*
|
||||
* @return bool Whether the given option exists
|
||||
*
|
||||
* @throws ValidationException if the schema failed to validate the given input
|
||||
*/
|
||||
public function exists(string $key): bool;
|
||||
}
|
22
vendor/league/config/src/ConfigurationProviderInterface.php
vendored
Normal file
22
vendor/league/config/src/ConfigurationProviderInterface.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
/**
|
||||
* Interface for a service which provides a readable configuration object
|
||||
*/
|
||||
interface ConfigurationProviderInterface
|
||||
{
|
||||
public function getConfiguration(): ConfigurationInterface;
|
||||
}
|
21
vendor/league/config/src/Exception/ConfigurationExceptionInterface.php
vendored
Normal file
21
vendor/league/config/src/Exception/ConfigurationExceptionInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config\Exception;
|
||||
|
||||
/**
|
||||
* Marker interface for any/all exceptions thrown by this library
|
||||
*/
|
||||
interface ConfigurationExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
46
vendor/league/config/src/Exception/InvalidConfigurationException.php
vendored
Normal file
46
vendor/league/config/src/Exception/InvalidConfigurationException.php
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config\Exception;
|
||||
|
||||
class InvalidConfigurationException extends \UnexpectedValueException implements ConfigurationExceptionInterface
|
||||
{
|
||||
/**
|
||||
* @param string $option Name/path of the option
|
||||
* @param mixed $valueGiven The invalid option that was provided
|
||||
* @param ?string $description Additional text describing the issue (optional)
|
||||
*/
|
||||
public static function forConfigOption(string $option, $valueGiven, ?string $description = null): self
|
||||
{
|
||||
$message = \sprintf('Invalid config option for "%s": %s', $option, self::getDebugValue($valueGiven));
|
||||
if ($description !== null) {
|
||||
$message .= \sprintf(' (%s)', $description);
|
||||
}
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function getDebugValue($value): string
|
||||
{
|
||||
if (\is_object($value)) {
|
||||
return \get_class($value);
|
||||
}
|
||||
|
||||
return \print_r($value, true);
|
||||
}
|
||||
}
|
33
vendor/league/config/src/Exception/UnknownOptionException.php
vendored
Normal file
33
vendor/league/config/src/Exception/UnknownOptionException.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
final class UnknownOptionException extends \InvalidArgumentException implements ConfigurationExceptionInterface
|
||||
{
|
||||
private string $path;
|
||||
|
||||
public function __construct(string $message, string $path, int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
37
vendor/league/config/src/Exception/ValidationException.php
vendored
Normal file
37
vendor/league/config/src/Exception/ValidationException.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config\Exception;
|
||||
|
||||
use Nette\Schema\ValidationException as NetteException;
|
||||
|
||||
final class ValidationException extends InvalidConfigurationException
|
||||
{
|
||||
/** @var string[] */
|
||||
private array $messages;
|
||||
|
||||
public function __construct(NetteException $innerException)
|
||||
{
|
||||
parent::__construct($innerException->getMessage(), (int) $innerException->getCode(), $innerException);
|
||||
|
||||
$this->messages = $innerException->getMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getMessages(): array
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
}
|
34
vendor/league/config/src/MutableConfigurationInterface.php
vendored
Normal file
34
vendor/league/config/src/MutableConfigurationInterface.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
use League\Config\Exception\UnknownOptionException;
|
||||
|
||||
/**
|
||||
* Interface for setting/merging user-defined configuration values into the configuration object
|
||||
*/
|
||||
interface MutableConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @throws UnknownOptionException if $key contains a nested path which doesn't point to an array value
|
||||
*/
|
||||
public function set(string $key, $value): void;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
*/
|
||||
public function merge(array $config = []): void;
|
||||
}
|
40
vendor/league/config/src/ReadOnlyConfiguration.php
vendored
Normal file
40
vendor/league/config/src/ReadOnlyConfiguration.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a given Configuration object
|
||||
*/
|
||||
final class ReadOnlyConfiguration implements ConfigurationInterface
|
||||
{
|
||||
private Configuration $config;
|
||||
|
||||
public function __construct(Configuration $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(string $key)
|
||||
{
|
||||
return $this->config->get($key);
|
||||
}
|
||||
|
||||
public function exists(string $key): bool
|
||||
{
|
||||
return $this->config->exists($key);
|
||||
}
|
||||
}
|
27
vendor/league/config/src/SchemaBuilderInterface.php
vendored
Normal file
27
vendor/league/config/src/SchemaBuilderInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/config package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Config;
|
||||
|
||||
use Nette\Schema\Schema;
|
||||
|
||||
/**
|
||||
* Interface that allows new schemas to be added to a configuration
|
||||
*/
|
||||
interface SchemaBuilderInterface
|
||||
{
|
||||
/**
|
||||
* Registers a new configuration schema at the given top-level key
|
||||
*/
|
||||
public function addSchema(string $key, Schema $schema): void;
|
||||
}
|
Reference in New Issue
Block a user