vendor/league/config/src/Configuration.php line 55

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the league/config package.
  5.  *
  6.  * (c) Colin O'Dell <colinodell@gmail.com>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace League\Config;
  12. use Dflydev\DotAccessData\Data;
  13. use Dflydev\DotAccessData\Exception\DataException;
  14. use Dflydev\DotAccessData\Exception\InvalidPathException;
  15. use Dflydev\DotAccessData\Exception\MissingPathException;
  16. use League\Config\Exception\UnknownOptionException;
  17. use League\Config\Exception\ValidationException;
  18. use Nette\Schema\Expect;
  19. use Nette\Schema\Processor;
  20. use Nette\Schema\Schema;
  21. use Nette\Schema\ValidationException as NetteValidationException;
  22. final class Configuration implements ConfigurationBuilderInterfaceConfigurationInterface
  23. {
  24.     /** @psalm-readonly */
  25.     private Data $userConfig;
  26.     /**
  27.      * @var array<string, Schema>
  28.      *
  29.      * @psalm-allow-private-mutation
  30.      */
  31.     private array $configSchemas = [];
  32.     /** @psalm-allow-private-mutation */
  33.     private ?Data $finalConfig null;
  34.     /**
  35.      * @var array<string, mixed>
  36.      *
  37.      * @psalm-allow-private-mutation
  38.      */
  39.     private array $cache = [];
  40.     /** @psalm-readonly */
  41.     private ConfigurationInterface $reader;
  42.     /**
  43.      * @param array<string, Schema> $baseSchemas
  44.      */
  45.     public function __construct(array $baseSchemas = [])
  46.     {
  47.         $this->configSchemas $baseSchemas;
  48.         $this->userConfig    = new Data();
  49.         $this->reader = new ReadOnlyConfiguration($this);
  50.     }
  51.     /**
  52.      * Registers a new configuration schema at the given top-level key
  53.      *
  54.      * @psalm-allow-private-mutation
  55.      */
  56.     public function addSchema(string $keySchema $schema): void
  57.     {
  58.         $this->invalidate();
  59.         $this->configSchemas[$key] = $schema;
  60.     }
  61.     /**
  62.      * {@inheritDoc}
  63.      *
  64.      * @psalm-allow-private-mutation
  65.      */
  66.     public function merge(array $config = []): void
  67.     {
  68.         $this->invalidate();
  69.         $this->userConfig->import($configData::REPLACE);
  70.     }
  71.     /**
  72.      * {@inheritDoc}
  73.      *
  74.      * @psalm-allow-private-mutation
  75.      */
  76.     public function set(string $key$value): void
  77.     {
  78.         $this->invalidate();
  79.         try {
  80.             $this->userConfig->set($key$value);
  81.         } catch (DataException $ex) {
  82.             throw new UnknownOptionException($ex->getMessage(), $key, (int) $ex->getCode(), $ex);
  83.         }
  84.     }
  85.     /**
  86.      * {@inheritDoc}
  87.      *
  88.      * @psalm-external-mutation-free
  89.      */
  90.     public function get(string $key)
  91.     {
  92.         if ($this->finalConfig === null) {
  93.             $this->finalConfig $this->build();
  94.         } elseif (\array_key_exists($key$this->cache)) {
  95.             return $this->cache[$key];
  96.         }
  97.         try {
  98.             return $this->cache[$key] = $this->finalConfig->get($key);
  99.         } catch (InvalidPathException MissingPathException $ex) {
  100.             throw new UnknownOptionException($ex->getMessage(), $key, (int) $ex->getCode(), $ex);
  101.         }
  102.     }
  103.     /**
  104.      * {@inheritDoc}
  105.      *
  106.      * @psalm-external-mutation-free
  107.      */
  108.     public function exists(string $key): bool
  109.     {
  110.         if ($this->finalConfig === null) {
  111.             $this->finalConfig $this->build();
  112.         } elseif (\array_key_exists($key$this->cache)) {
  113.             return true;
  114.         }
  115.         try {
  116.             return $this->finalConfig->has($key);
  117.         } catch (InvalidPathException $ex) {
  118.             return false;
  119.         }
  120.     }
  121.     /**
  122.      * @psalm-mutation-free
  123.      */
  124.     public function reader(): ConfigurationInterface
  125.     {
  126.         return $this->reader;
  127.     }
  128.     /**
  129.      * @psalm-external-mutation-free
  130.      */
  131.     private function invalidate(): void
  132.     {
  133.         $this->cache       = [];
  134.         $this->finalConfig null;
  135.     }
  136.     /**
  137.      * Applies the schema against the configuration to return the final configuration
  138.      *
  139.      * @throws ValidationException
  140.      *
  141.      * @psalm-allow-private-mutation
  142.      */
  143.     private function build(): Data
  144.     {
  145.         try {
  146.             $schema    Expect::structure($this->configSchemas);
  147.             $processor = new Processor();
  148.             $processed $processor->process($schema$this->userConfig->export());
  149.             $this->raiseAnyDeprecationNotices($processor->getWarnings());
  150.             return $this->finalConfig = new Data(self::convertStdClassesToArrays($processed));
  151.         } catch (NetteValidationException $ex) {
  152.             throw new ValidationException($ex);
  153.         }
  154.     }
  155.     /**
  156.      * Recursively converts stdClass instances to arrays
  157.      *
  158.      * @param mixed $data
  159.      *
  160.      * @return mixed
  161.      *
  162.      * @psalm-pure
  163.      */
  164.     private static function convertStdClassesToArrays($data)
  165.     {
  166.         if ($data instanceof \stdClass) {
  167.             $data = (array) $data;
  168.         }
  169.         if (\is_array($data)) {
  170.             foreach ($data as $k => $v) {
  171.                 $data[$k] = self::convertStdClassesToArrays($v);
  172.             }
  173.         }
  174.         return $data;
  175.     }
  176.     /**
  177.      * @param string[] $warnings
  178.      */
  179.     private function raiseAnyDeprecationNotices(array $warnings): void
  180.     {
  181.         foreach ($warnings as $warning) {
  182.             @\trigger_error($warning\E_USER_DEPRECATED);
  183.         }
  184.     }
  185. }