Config::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Igni\Application;
4
5
use Igni\Application\Exception\ConfigException;
6
7
/**
8
 * Application's config container.
9
 * Treats dots as an operator for accessing nested values.
10
 * If constant name is put in curly braces as a value, it wil be replaced
11
 * to the constant value.
12
 *
13
 * @example:
14
 * // Example usage.
15
 * $config = new Config();
16
 * $config->set('some.key', true);
17
 * $some = $config->get('some'); // returns ['key' => true]
18
 *
19
 * @package Igni\Application
20
 */
21
class Config
22
{
23
    /**
24
     * @var array
25
     */
26
    private $config;
27
28
    /**
29
     * Config constructor.
30
     *
31
     * @param array $config
32
     */
33 31
    public function __construct(array $config = [])
34
    {
35 31
        $this->config = $config;
36 31
    }
37
38
    /**
39
     * Checks if config key exists.
40
     *
41
     * @param string $key
42
     * @return bool
43
     */
44
    public function has(string $key): bool
45
    {
46
        return $this->lookup($key) !== null;
47
    }
48
49 4
    private function lookup(string $key)
50
    {
51 4
        $result = $this->config;
52 4
        $key = explode('.', $key);
53 4
        foreach($key as $part) {
54 4
            if (!is_array($result) || !isset($result[$part])) {
55
                return null;
56
            }
57 4
            $result = $result[$part];
58
        }
59
60 4
        return $result;
61
    }
62
63
    /**
64
     * Gets value behind the key, or returns $default value if path does not exists.
65
     *
66
     * @param string $key
67
     * @param null $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
68
     * @return null|string|string[]
69
     */
70 4
    public function get(string $key, $default = null)
71
    {
72 4
        $result = $this->lookup($key);
73 4
        return $result === null ? $default : $this->fetchConstants($result);
74
    }
75
76
    /**
77
     * Merges one instance of Config class into current one and
78
     * returns current instance.
79
     *
80
     * @param Config $config
81
     * @return Config
82
     */
83 1
    public function merge(Config $config): Config
84
    {
85 1
        $this->config = array_merge_recursive($this->config, $config->config);
86
87 1
        return $this;
88
    }
89
90
    /**
91
     * Returns new instance of the config containing only values from the
92
     * given namespace.
93
     *
94
     * @param string $namespace
95
     * @return Config
96
     */
97 2
    public function extract(string $namespace): Config
98
    {
99 2
        $extracted = $this->get($namespace);
100 2
        if (!is_array($extracted)) {
101 1
            throw ConfigException::forExtractionFailure($namespace);
102
        }
103
104 1
        return new self($extracted);
105
    }
106
107
    /**
108
     * Sets new value.
109
     *
110
     * @param string $key
111
     * @param $value
112
     */
113 5
    public function set(string $key, $value): void
114
    {
115 5
        $key = explode('.', $key);
116 5
        $last = array_pop($key);
117 5
        $result = &$this->config;
118
119 5
        foreach ($key as $part) {
120 4
            if (!isset($result[$part]) || !is_array($result[$part])) {
121 4
                $result[$part] = [];
122
            }
123 4
            $result = &$result[$part];
124
        }
125 5
        $result[$last] = $value;
126 5
    }
127
128
    /**
129
     * Returns array representation of the config.
130
     *
131
     * @return array
132
     */
133 2
    public function toArray(): array
134
    {
135 2
        return $this->config;
136
    }
137
138
    /**
139
     * Returns flat array representation of the config, all nested values are stored
140
     * in keys containing path separated by dot.
141
     *
142
     * @return array
143
     */
144 2
    public function toFlatArray(): array
145
    {
146 2
        return self::flatten($this->config);
147
    }
148
149 2
    private static function flatten(array &$array, string $prefix = ''): array
150
    {
151 2
        $values = [];
152 2
        foreach ($array as $key => &$value) {
153 2
            if (is_array($value) && !empty($value)) {
154 2
                $values = array_merge($values, self::flatten($value, $prefix . $key . '.'));
155
            } else {
156 2
                $values[$prefix . $key] = $value;
157
            }
158
        }
159
160 2
        return $values;
161
    }
162
163 4
    private function fetchConstants($value)
164
    {
165 4
        if (!is_string($value)) {
166 3
            return $value;
167
        }
168 1
        return preg_replace_callback(
169 1
            '#\$\{([^{}]*)\}#',
170
            function($matches) {
171 1
                if (defined($matches[1])) {
172 1
                    return constant($matches[1]);
173
                }
174
                return $matches[0];
175 1
            },
176 1
            $value
177
        );
178
    }
179
}
180