Passed
Push — develop ( 08ee0f...f2aabe )
by nguereza
01:54
created

AbstractConfiguration::checkType()   B

Complexity

Conditions 8
Paths 17

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 19
c 0
b 0
f 0
nc 17
nop 2
dl 0
loc 30
rs 8.4444
1
<?php
2
3
/**
4
 * Platine Stdlib
5
 *
6
 * Platine Stdlib is a the collection of frequently used php features
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Stdlib
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file AbstractConfiguration.php
33
 *
34
 *  The base class for application
35
 *
36
 *  @package    Platine\Stdlib\Config
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   http://www.iacademy.cf
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Stdlib\Config;
48
49
use Error;
50
use InvalidArgumentException;
51
use Platine\Stdlib\Contract\ConfigurationInterface;
52
use Platine\Stdlib\Helper\Arr;
53
use Platine\Stdlib\Helper\Str;
54
55
/**
56
 * Class AbstractConfiguration
57
 * @package Platine\Stdlib\Config
58
 */
59
abstract class AbstractConfiguration implements ConfigurationInterface
60
{
61
62
    /**
63
     * The raw configuration array
64
     * @var array<string, mixed>
65
     */
66
    protected array $config = [];
67
68
    /**
69
     * {@inheritedoc}
70
     */
71
    public function __construct(array $config = [])
72
    {
73
        $configuration = array_merge($this->getDefault(), $config);
74
        $this->load($configuration);
75
    }
76
77
    /**
78
     * {@inheritedoc}
79
     */
80
    public function get(string $name)
81
    {
82
        if (!$this->has($name)) {
83
            throw new InvalidArgumentException(sprintf(
84
                'Configuration [%s] does not exist',
85
                $name
86
            ));
87
        }
88
89
        return Arr::get($this->config, $name);
90
    }
91
92
    /**
93
     * {@inheritedoc}
94
     */
95
    public function has(string $name): bool
96
    {
97
        return Arr::has($this->config, $name);
98
    }
99
100
    /**
101
     * {@inheritedoc}
102
     */
103
    public function load(array $config): void
104
    {
105
        $this->config = $config;
106
        $rules = $this->getValidationRules();
107
        $setters = $this->getSetterMaps();
108
109
        foreach ($rules as $name => $type) {
110
            $this->checkType($name, $type);
111
        }
112
113
        foreach ($config as $name => $value) {
114
            $key = Str::camel($name, true);
115
116
            if (Arr::has($setters, $key)) {
117
                $method = Arr::get($setters, $key);
118
                $this->{$method}($value);
119
            } else {
120
                $setterMethod = 'set' . ucfirst($key);
121
                if (method_exists($this, $setterMethod)) {
122
                    $this->{$setterMethod}($value);
123
                } else {
124
                    $this->{$key} = $value;
125
                }
126
            }
127
        }
128
    }
129
130
    /**
131
     * {@inheritedoc}
132
     */
133
    public function getValidationRules(): array
134
    {
135
        return [];
136
    }
137
138
    /**
139
     * {@inheritedoc}
140
     */
141
    public function getSetterMaps(): array
142
    {
143
        return [];
144
    }
145
146
    /**
147
     * {@inheritedoc}
148
     */
149
    public function getDefault(): array
150
    {
151
        return [];
152
    }
153
154
    /**
155
     * Check the configuration for the given type
156
     * @param string $key the configuration
157
     *  key to be checked can be dot notation
158
     * @param string $type
159
     * @return void
160
     */
161
    private function checkType(string $key, string $type): void
162
    {
163
        if (!Arr::has($this->config, $key)) {
164
            return;
165
        }
166
167
        $value = Arr::get($this->config, $key, null);
168
169
        $valueType = gettype($value);
170
        $className = null;
171
        if (strpos($type, 'object::') === 0) {
172
            $className = substr($type, 8);
173
        }
174
175
        $error = null;
176
177
        if ($className !== null) {
178
            if (!($value instanceof $className)) {
179
                $error = 'Invalid configuration [%s] instance value, expected [%s], but got [%s]';
180
            }
181
        } elseif ($type !== $valueType) {
182
            $error = 'Invalid configuration [%s] value, expected [%s], but got [%s]';
183
        }
184
185
        if ($error !== null) {
186
            throw new Error(sprintf(
187
                $error,
188
                Str::snake($key),
189
                $className ?? $type,
190
                is_object($value) ? get_class($value) : gettype($value)
191
            ));
192
        }
193
    }
194
}
195