Completed
Push — latest ( 7e49ae...5ac9c7 )
by Colin
20s queued 12s
created

src/Configuration/Configuration.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace League\CommonMark\Configuration;
15
16
use Dflydev\DotAccessData\Data;
17
use Dflydev\DotAccessData\Exception\InvalidPathException;
18
use Dflydev\DotAccessData\Exception\MissingPathException;
19
use League\CommonMark\Exception\InvalidConfigurationException;
20
use Nette\Schema\Elements\Structure;
21
use Nette\Schema\Expect;
22
use Nette\Schema\Processor;
23
use Nette\Schema\Schema;
24
use Nette\Schema\ValidationException;
25
26
final class Configuration implements ConfigurationBuilderInterface, ConfigurationInterface
27
{
28
    /**
29
     * @var Data
30
     *
31
     * @psalm-readonly
32
     */
33
    private $userConfig;
34
35
    /** @var array<string, Schema> */
36
    private $configSchemas = [];
37
38
    /** @var Data|null */
39
    private $finalConfig;
40
41
    /** @var array<string, mixed> */
42
    private $cache = [];
43
44
    /**
45
     * @var ConfigurationInterface
46
     *
47
     * @psalm-readonly
48
     */
49
    private $reader;
50
51
    /**
52
     * @param array<string, Schema> $baseSchemas
53
     */
54 3351
    public function __construct(array $baseSchemas = [])
55
    {
56 3351
        $this->configSchemas = $baseSchemas;
57 3351
        $this->userConfig    = new Data();
58
59 3351
        $this->reader = new ReadOnlyConfiguration($this);
60 3351
    }
61
62
    /**
63
     * Registers a new configuration schema at the given top-level key
64
     */
65 3225
    public function addSchema(string $key, Schema $schema): void
66
    {
67 3225
        $this->invalidate();
68
69 3225
        if ($schema instanceof Structure) {
70 3216
            $schema->castTo('array');
71
        }
72
73 3225
        $this->configSchemas[$key] = $schema;
74 3225
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 3324
    public function merge(array $config = []): void
80
    {
81 3324
        $this->invalidate();
82
83 3324
        $this->userConfig->import($config, Data::REPLACE);
84 3324
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 21
    public function set(string $key, $value): void
90
    {
91 21
        $this->invalidate();
92
93 21
        $this->userConfig->set($key, $value);
94 21
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99 3237
    public function get(string $key)
100
    {
101 3237
        if ($this->finalConfig === null) {
102 3237
            $this->finalConfig = $this->build();
103 3015
        } elseif (\array_key_exists($key, $this->cache)) {
104 954
            return $this->cache[$key];
105
        }
106
107
        try {
108 3210
            return $this->cache[$key] = $this->finalConfig->get($key);
109 6
        } catch (InvalidPathException | MissingPathException $ex) {
110 6
            throw InvalidConfigurationException::missingOption($key);
111
        }
112
    }
113
114 3
    public function exists(string $key): bool
115
    {
116 3
        if ($this->finalConfig === null) {
117 3
            $this->finalConfig = $this->build();
118 3
        } elseif (\array_key_exists($key, $this->cache)) {
119
            return true;
120
        }
121
122 3
        return $this->finalConfig->has($key);
123
    }
124
125 3240
    public function reader(): ConfigurationInterface
126
    {
127 3240
        return $this->reader;
128
    }
129
130 3345
    private function invalidate(): void
131
    {
132 3345
        $this->cache       = [];
133 3345
        $this->finalConfig = null;
134 3345
    }
135
136
    /**
137
     * Applies the schema against the configuration to return the final configuration
138
     */
139 3240
    private function build(): Data
140
    {
141
        try {
142 3240
            $schema    = Expect::structure($this->configSchemas)->castTo('array');
143 3240
            $processor = new Processor();
144 3240
            $config    = new Data($processor->process($schema, $this->userConfig->export()));
0 ignored issues
show
It seems like $processor->process($sch...->userConfig->export()) can also be of type null; however, parameter $data of Dflydev\DotAccessData\Data::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
            $config    = new Data(/** @scrutinizer ignore-type */ $processor->process($schema, $this->userConfig->export()));
Loading history...
145
146 3213
            return $this->finalConfig = $config;
147 33
        } catch (ValidationException $ex) {
148 33
            throw InvalidConfigurationException::fromValidation($ex);
149
        }
150
    }
151
}
152