Issues (10)

src/Config.php (2 issues)

1
<?php
2
/**
3
 * Bright Nucleus Config Component.
4
 *
5
 * @package   BrightNucleus\Config
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\Config;
13
14
use BrightNucleus\Config\ConfigSchemaInterface as Schema;
15
use BrightNucleus\Config\ConfigValidatorInterface as Validator;
16
use BrightNucleus\Config\Exception\FailedToInstantiateParentException;
17
use BrightNucleus\Config\Exception\FailedToLoadConfigException;
18
use BrightNucleus\Config\Exception\FailedToResolveConfigException;
19
use BrightNucleus\Config\Exception\InvalidConfigException;
20
use BrightNucleus\Config\Exception\InvalidConfigurationSourceException;
21
use Exception;
22
use Symfony\Component\OptionsResolver\OptionsResolver;
23
24
/**
25
 * Generic implementation of a Config object.
26
 *
27
 * @since   0.1.0
28
 *
29
 * @package BrightNucleus\Config
30
 * @author  Alain Schlesser <[email protected]>
31
 */
32
class Config extends AbstractConfig
33
{
34
35
    /**
36
     * The schema of the Config file.
37
     *
38
     * @var Schema
39
     */
40
    protected $schema;
41
42
    /**
43
     * The Validator class that gets asked to do the validation of the config.
44
     *
45
     * @since 0.1.0
46
     *
47
     * @var Validator
48
     */
49
    protected $validator;
50
51
    /**
52
     * Instantiate the Config object.
53
     *
54
     * It accepts either an array with the configuration settings, or a
55
     * filename pointing to a PHP file it can include.
56
     *
57
     * @since 0.1.0
58
     * @since 0.1.6 Accepts a delimiter to parse configuration keys.
59
     *
60
     * @param array|string         $config    Array with settings or filename for the
61
     *                                        settings file.
62
     * @param Schema|null          $schema    Optional. Config that contains default
63
     *                                        values that can get overwritten.
64
     * @param Validator|null       $validator Optional. Validator class that does the
65
     *                                        actual validation.
66
     * @param string[]|string|null $delimiter A string or array of strings that are used as delimiters to parse
67
     *                                        configuration keys. Defaults to "\", "/" & ".".
68
     *
69
     * @throws InvalidConfigurationSourceException If the config source is not a string or array.
70
     * @throws FailedToInstantiateParentException  If the parent class could not be instantiated.
71
     * @throws FailedToLoadConfigException         If loading of the config source failed.
72
     * @throws FailedToResolveConfigException      If the config file could not be resolved.
73
     * @throws InvalidConfigException              If the config file is not valid.
74
     */
75 11
    public function __construct(
76
        $config,
77
        ?Schema $schema = null,
78
        ?Validator $validator = null,
79
        $delimiter = null
80
    ) {
81 11
        $this->schema    = $schema;
82 11
        $this->validator = $validator;
83
84
        // Make sure $config is either a string or array.
85 11
        if (! (is_string($config) || is_array($config))) {
0 ignored issues
show
The condition is_array($config) is always true.
Loading history...
86 1
            throw new InvalidConfigurationSourceException(
87
                sprintf(
88 1
                    _('Invalid configuration source: %1$s'),
89 1
                    print_r($config, true)
90
                )
91
            );
92
        }
93
94 10
        if (is_string($config)) {
95 6
            $config = Loader::load($config);
96
        }
97
98
        // Run the $config through the OptionsResolver.
99 8
        $config = $this->resolveOptions($config);
100
101
        // Instantiate the parent class.
102
        try {
103 8
            parent::__construct($config, $delimiter);
104
        } catch (Exception $exception) {
105
            throw new FailedToInstantiateParentException(
106
                sprintf(
107
                    _('Could not instantiate the configuration through its parent. Reason: %1$s'),
108
                    $exception->getMessage()
109
                )
110
            );
111
        }
112
113
        // Finally, validate the resulting config.
114 8
        if (! $this->isValid()) {
115 1
            throw new InvalidConfigException(
116
                sprintf(
117 1
                    _('ConfigInterface file is not valid: %1$s'),
118 1
                    print_r($config, true)
0 ignored issues
show
It seems like print_r($config, true) can also be of type true; however, parameter $values of sprintf() does only seem to accept double|integer|string, 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

118
                    /** @scrutinizer ignore-type */ print_r($config, true)
Loading history...
119
                )
120
            );
121
        }
122 8
    }
123
124
    /**
125
     * Validate the Config file.
126
     *
127
     * @since  0.1.0
128
     *
129
     * @return boolean
130
     */
131 4
    public function isValid()
132
    {
133 4
        if ($this->validator) {
134 1
            return $this->validator->isValid($this);
135
        }
136
137 4
        return true;
138
    }
139
140
    /**
141
     * Process the passed-in defaults and merge them with the new values, while
142
     * checking that all required options are set.
143
     *
144
     * @since 0.1.0
145
     *
146
     * @param array $config Configuration settings to resolve.
147
     *
148
     * @return array Resolved configuration settings.
149
     * @throws FailedToResolveConfigException If there are errors while resolving the options.
150
     */
151 6
    protected function resolveOptions($config)
152
    {
153 6
        if (! $this->schema) {
154 6
            return $config;
155
        }
156
157
        try {
158 2
            $resolver = new OptionsResolver();
159 2
            if ($this->configureOptions($resolver)) {
160 2
                $config = $resolver->resolve($config);
161
            }
162 1
        } catch (Exception $exception) {
163 1
            throw new FailedToResolveConfigException(
164
                sprintf(
165 1
                    _('Error while resolving config options: %1$s'),
166 1
                    $exception->getMessage()
167
                )
168
            );
169
        }
170
171 1
        return $config;
172
    }
173
174
    /**
175
     * Configure the possible and required options for the Config.
176
     *
177
     * This should return a bool to let the resolve_options() know whether the
178
     * actual resolving needs to be done or not.
179
     *
180
     * @since 0.1.0
181
     *
182
     * @param OptionsResolver $resolver Reference to the OptionsResolver
183
     *                                  instance.
184
     *
185
     * @return bool Whether to do the resolving.
186
     * @throws FailedToResolveConfigException If there are errors while processing.
187
     */
188 2
    protected function configureOptions(OptionsResolver $resolver)
189
    {
190 2
        $defined  = $this->schema->getDefinedOptions();
191 2
        $defaults = $this->schema->getDefaultOptions();
192 2
        $required = $this->schema->getRequiredOptions();
193
194 2
        if (! $defined && ! $defaults && ! $required) {
195
            return false;
196
        }
197
198
        try {
199 2
            if ($defined) {
200 2
                $resolver->setDefined($defined);
201
            }
202 2
            if ($defaults) {
203 2
                $resolver->setDefaults($defaults);
204
            }
205 2
            if ($required) {
206 2
                $resolver->setRequired($required);
207
            }
208
        } catch (Exception $exception) {
209
            throw new FailedToResolveConfigException(
210
                sprintf(
211
                    _('Error while processing config options: %1$s'),
212
                    $exception->getMessage()
213
                )
214
            );
215
        }
216
217 2
        return true;
218
    }
219
}
220