Passed
Push — master ( 5f88dd...10f6bc )
by Smoren
12:50
created

ContainerAccessHelper::getRefFromObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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