Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
19 / 19 |
|
100.00% |
7 / 7 |
CRAP | |
100.00% |
1 / 1 |
ArrayConfig | |
100.00% |
19 / 19 |
|
100.00% |
7 / 7 |
12 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
has | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
set | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
remove | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
getIterator | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
toArray | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | /** |
6 | * This file is part of php-fast-forward/config. |
7 | * |
8 | * This source file is subject to the license bundled |
9 | * with this source code in the file LICENSE. |
10 | * |
11 | * @link https://github.com/php-fast-forward/config |
12 | * @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <github@mentordosnerds.com> |
13 | * @license https://opensource.org/licenses/MIT MIT License |
14 | */ |
15 | |
16 | namespace FastForward\Config; |
17 | |
18 | use Dflydev\DotAccessData\Data; |
19 | use FastForward\Config\Exception\InvalidArgumentException; |
20 | use FastForward\Config\Helper\ConfigHelper; |
21 | |
22 | /** |
23 | * Class ArrayConfig. |
24 | * |
25 | * Provides a configuration management system with dot notation access. |
26 | * This class SHALL encapsulate configuration data using the DotAccessData library. |
27 | * It MUST support nested keys and provide export, iteration, and dynamic update capabilities. |
28 | * |
29 | * @package FastForward\Config |
30 | */ |
31 | final class ArrayConfig implements ConfigInterface |
32 | { |
33 | use ArrayAccessConfigTrait; |
34 | |
35 | /** |
36 | * @var Data internal configuration storage instance |
37 | */ |
38 | private Data $data; |
39 | |
40 | /** |
41 | * Constructs the ArrayConfig instance. |
42 | * |
43 | * This constructor SHALL initialize the internal configuration store using normalized keys. |
44 | * |
45 | * @param array $config an optional initial configuration array |
46 | */ |
47 | public function __construct(array $config = []) |
48 | { |
49 | $this->data = new Data( |
50 | data: ConfigHelper::normalize($config), |
51 | ); |
52 | } |
53 | |
54 | /** |
55 | * Determines whether the given configuration key exists. |
56 | * |
57 | * @param string $key the dot-notation configuration key to check |
58 | * |
59 | * @return bool TRUE if the key exists, FALSE otherwise |
60 | */ |
61 | public function has(string $key): bool |
62 | { |
63 | return $this->data->has($key); |
64 | } |
65 | |
66 | /** |
67 | * Retrieves a value from the configuration. |
68 | * |
69 | * If the value is a nested associative array, a new instance of ArrayConfig SHALL be returned. |
70 | * If the key is not found and no default is provided, a MissingPathException SHOULD be thrown. |
71 | * |
72 | * @param string $key the configuration key to retrieve |
73 | * @param mixed $default the default value to return if the key does not exist |
74 | * |
75 | * @return mixed|self the configuration value, or a nested ArrayConfig instance |
76 | */ |
77 | public function get(string $key, mixed $default = null): mixed |
78 | { |
79 | $value = $this->data->get($key, $default); |
80 | |
81 | if (ConfigHelper::isAssoc($value)) { |
82 | return new self($value); |
83 | } |
84 | |
85 | return $value; |
86 | } |
87 | |
88 | /** |
89 | * Sets configuration values into the internal data store. |
90 | * |
91 | * If a value is provided, the key MUST be a string. If the input is an associative array |
92 | * or another ConfigInterface instance, it SHALL be normalized before insertion. |
93 | * |
94 | * @param array|ConfigInterface|string $key the configuration key(s) or configuration object |
95 | * @param null|mixed $value the value to assign to the specified key, if applicable |
96 | * |
97 | * @throws InvalidArgumentException if the key is not a string when a value is provided |
98 | */ |
99 | public function set(array|ConfigInterface|string $key, mixed $value = null): void |
100 | { |
101 | if (!empty($value)) { |
102 | if (!\is_string($key)) { |
103 | throw InvalidArgumentException::forNonStringKeyWithValue(); |
104 | } |
105 | |
106 | $key = [$key => $value]; |
107 | } |
108 | |
109 | if ($key instanceof ConfigInterface) { |
110 | $key = $key->toArray(); |
111 | } |
112 | |
113 | $this->data->import(ConfigHelper::normalize($key)); |
114 | } |
115 | |
116 | /** |
117 | * Removes a configuration key and its associated value. |
118 | * |
119 | * If the key does not exist, this method SHALL do nothing. |
120 | * |
121 | * @param string $key the configuration key to remove |
122 | */ |
123 | public function remove(string $key): void |
124 | { |
125 | if ($this->has($key)) { |
126 | $this->data->remove($key); |
127 | } |
128 | } |
129 | |
130 | /** |
131 | * Retrieves a traversable set of flattened configuration data. |
132 | * |
133 | * This method SHALL return an iterator where each key represents |
134 | * the nested path in dot notation, and each value is the corresponding value. |
135 | * |
136 | * For example: |
137 | * ['database' => ['host' => 'localhost']] becomes ['database.host' => 'localhost']. |
138 | * |
139 | * @return \Traversable<string, mixed> an iterator of flattened key-value pairs |
140 | */ |
141 | public function getIterator(): \Traversable |
142 | { |
143 | return ConfigHelper::flatten($this->toArray()); |
144 | } |
145 | |
146 | /** |
147 | * Converts the entire configuration to an associative array. |
148 | * |
149 | * This method MUST export the configuration in its current state. |
150 | * |
151 | * @return array the exported configuration array |
152 | */ |
153 | public function toArray(): array |
154 | { |
155 | return $this->data->export(); |
156 | } |
157 | } |