Passed
Push — master ( 6434d9...1aee48 )
by Smoren
02:19
created

ContainerAccessHelper::exist()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 4
nop 2
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Schemator\Helpers;
6
7
use ArrayAccess;
8
use stdClass;
9
10
/**
11
 * Tool for map-like accessing of different containers by string keys.
12
 *
13
 * Can access:
14
 *  - properties of objects (by name or by getter);
15
 *  - elements of arrays and ArrayAccess objects (by key).
16
 *
17
 * @template TKey of string|int
18
 * @template TValue of mixed
19
 */
20
class ContainerAccessHelper
21
{
22
    /**
23
     * Returns value from the container by key or default value if key does not exist or not accessible.
24
     *
25
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
26
     * @param TKey $key
0 ignored issues
show
Bug introduced by
The type Smoren\Schemator\Helpers\TKey was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
     * @param TValue|null $defaultValue
0 ignored issues
show
Bug introduced by
The type Smoren\Schemator\Helpers\TValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
     *
29
     * @return TValue|null
30
     *
31
     * @throws \InvalidArgumentException
32
     */
33
    public static function get($container, $key, $defaultValue = null)
34
    {
35
        switch (true) {
36
            case is_array($container):
37
                return static::getFromArray($container, $key, $defaultValue);
38
            case $container instanceof ArrayAccess:
39
                return static::getFromArrayAccess($container, $key, $defaultValue);
40
            case is_object($container):
41
                return static::getFromObject($container, $key, $defaultValue);
42
        }
43
44
        return $defaultValue;
45
    }
46
47
    /**
48
     * Returns value from the container by key (sets and returns default value if key does not exist).
49
     *
50
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
51
     * @param TKey $key
52
     * @param TValue|null $defaultValue
53
     *
54
     * @return TValue|null
55
     *
56
     * @throws \InvalidArgumentException
57
     */
58
    public static function &getRef(&$container, $key, $defaultValue = null)
59
    {
60
        switch (true) {
61
            case is_array($container):
62
                return static::getRefFromArray($container, $key, $defaultValue);
63
            case $container instanceof ArrayAccess:
64
                return static::getRefFromArrayAccess($container, $key, $defaultValue);
65
            case is_object($container):
66
                return static::getRefFromObject($container, $key, $defaultValue);
67
        }
68
69
        $type = gettype($container);
70
        throw new \InvalidArgumentException("Cannot get ref to key '{$key}' from container of type '{$type}'");
71
    }
72
73
    /**
74
     * Sets value to the container by key.
75
     *
76
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object $container
77
     * @param TKey $key
78
     * @param TValue $value
79
     *
80
     * @return void
81
     *
82
     * @throws \InvalidArgumentException
83
     */
84
    public static function set(&$container, $key, $value): void
85
    {
86
        switch (true) {
87
            case is_array($container):
88
            case $container instanceof ArrayAccess:
89
                $container[$key] = $value;
90
                break;
91
            case is_object($container):
92
                static::setToObject($container, $key, $value);
93
                break;
94
            default:
95
                $type = gettype($container);
96
                throw new \InvalidArgumentException("Cannot set value to variable of type '{$type}'");
97
        }
98
    }
99
100
    /**
101
     * Deletes key from the container.
102
     *
103
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object $container
104
     * @param TKey $key
105
     *
106
     * @return void
107
     *
108
     * @throws \InvalidArgumentException
109
     */
110
    public static function delete(&$container, $key): void
111
    {
112
        switch (true) {
113
            case is_array($container):
114
                if (array_key_exists($key, $container)) {
115
                    unset($container[$key]);
116
                }
117
                break;
118
            case $container instanceof ArrayAccess:
119
                if ($container->offsetExists($key)) {
120
                    $container->offsetUnset($key);
121
                }
122
                break;
123
            case $container instanceof stdClass:
124
                unset($container->{$key});
125
                break;
126
            default:
127
                $type = gettype($container);
128
                throw new \InvalidArgumentException("Cannot delete key from variable of type '{$type}'");
129
        }
130
    }
131
132
    /**
133
     * Returns true if the accessible key exists in the container.
134
     *
135
     * @param array<TKey, TValue>|ArrayAccess<TKey, TValue>|object|mixed $container
136
     * @param TKey $key
137
     *
138
     * @return bool
139
     */
140
    public static function exist($container, $key): bool
141
    {
142
        switch (true) {
143
            case is_array($container):
144
                return static::existsInArray($container, $key);
145
            case $container instanceof ArrayAccess:
146
                return static::existsInArrayAccess($container, $key);
147
            case is_object($container):
148
                return static::existsInObject($container, $key);
149
        }
150
        return false;
151
    }
152
153
    /**
154
     * @param mixed $container
155
     * @return bool
156
     */
157
    public static function isArrayAccessible($container): bool
158
    {
159
        return is_array($container) || ($container instanceof ArrayAccess);
160
    }
161
162
    /**
163
     * Returns value from the array by key or default value if key does not exist.
164
     *
165
     * @param array<TKey, TValue> $container
166
     * @param TKey $key
167
     * @param TValue|null $defaultValue
168
     *
169
     * @return TValue|null
170
     */
171
    protected static function getFromArray(array $container, $key, $defaultValue)
172
    {
173
        if (static::existsInArray($container, $key)) {
174
            return $container[$key];
175
        }
176
177
        return $defaultValue ?? null;
178
    }
179
180
    /**
181
     * Returns reference to value from the array by key (sets and returns default value if key does not exist).
182
     *
183
     * @param array<TKey, TValue> $container
184
     * @param TKey $key
185
     * @param TValue|null $defaultValue
186
     *
187
     * @return TValue|null
188
     */
189
    protected static function &getRefFromArray(array &$container, $key, $defaultValue)
190
    {
191
        if (!static::existsInArray($container, $key)) {
192
            $container[$key] = $defaultValue;
193
        }
194
195
        return $container[$key];
196
    }
197
198
    /**
199
     * Returns true if the key exists in the array.
200
     *
201
     * @param array<TKey, TValue> $container
202
     * @param TKey $key
203
     *
204
     * @return bool
205
     */
206
    protected static function existsInArray(array $container, $key): bool
207
    {
208
        return array_key_exists($key, $container);
209
    }
210
211
    /**
212
     * Returns value from the ArrayAccess object by key or default value if key does not exist.
213
     *
214
     * @param ArrayAccess<TKey, TValue> $container
215
     * @param TKey $key
216
     * @param TValue|null $defaultValue
217
     *
218
     * @return TValue|null
219
     */
220
    protected static function getFromArrayAccess(ArrayAccess $container, $key, $defaultValue)
221
    {
222
        if (static::existsInArrayAccess($container, $key)) {
223
            return $container[$key];
224
        }
225
226
        return $defaultValue ?? null;
227
    }
228
229
    /**
230
     * Returns reference to value from the ArrayAccess object by key
231
     * (sets and returns default value if key does not exist).
232
     *
233
     * @param ArrayAccess<TKey, TValue> $container
234
     * @param TKey $key
235
     * @param TValue|null $defaultValue
236
     *
237
     * @return TValue|null
238
     */
239
    protected static function &getRefFromArrayAccess(ArrayAccess &$container, $key, $defaultValue)
240
    {
241
        if (!static::existsInArrayAccess($container, $key)) {
242
            /** @var TValue $defaultValue */
243
            $container[$key] = $defaultValue;
244
        }
245
246
        return $container[$key];
247
    }
248
249
    /**
250
     * Returns true if the key exists in the ArrayAccess object.
251
     *
252
     * @param ArrayAccess<TKey, TValue> $container
253
     * @param TKey $key
254
     *
255
     * @return bool
256
     */
257
    protected static function existsInArrayAccess(ArrayAccess $container, $key): bool
258
    {
259
        return $container->offsetExists($key);
260
    }
261
262
    /**
263
     * Returns value from the object by key or default value if key does not exist.
264
     *
265
     * @param object $container
266
     * @param TKey $key
267
     * @param TValue|null $defaultValue
268
     *
269
     * @return TValue|null
270
     *
271
     * @throws \InvalidArgumentException
272
     */
273
    protected static function getFromObject(object $container, $key, $defaultValue)
274
    {
275
        if (ObjectAccessHelper::hasReadableProperty($container, strval($key))) {
276
            return ObjectAccessHelper::getPropertyValue($container, strval($key));
277
        }
278
279
        return $defaultValue;
280
    }
281
282
    /**
283
     * Returns value from the object by key or default value if key does not exist.
284
     *
285
     * @param object $container
286
     * @param TKey $key
287
     * @param TValue|null $defaultValue
288
     *
289
     * @return TValue|null
290
     *
291
     * @throws \InvalidArgumentException
292
     */
293
    protected static function &getRefFromObject(object &$container, $key, $defaultValue)
294
    {
295
        return ObjectAccessHelper::getPropertyRef($container, strval($key), $defaultValue);
296
    }
297
298
    /**
299
     * Sets property value to the object if it is writable by name or by setter.
300
     *
301
     * @param object $container
302
     * @param TKey $key
303
     * @param TValue $value
304
     *
305
     * @return void
306
     *
307
     * @throws \InvalidArgumentException
308
     */
309
    protected static function setToObject(object $container, $key, $value): void
310
    {
311
        if (!ObjectAccessHelper::hasWritableProperty($container, strval($key)) && !($container instanceof stdClass)) {
312
            $className = get_class($container);
313
            throw new \InvalidArgumentException("Property '{$className}::{$key}' is not writable");
314
        }
315
316
        ObjectAccessHelper::setPropertyValue($container, strval($key), $value);
317
    }
318
319
    /**
320
     * Returns true if the key exists in the object.
321
     *
322
     * @param object $container
323
     * @param TKey $key
324
     *
325
     * @return bool
326
     */
327
    protected static function existsInObject(object $container, $key): bool
328
    {
329
        return ObjectAccessHelper::hasReadableProperty($container, strval($key));
330
    }
331
}
332