ArrayHelper::normalizeFilter()   B
last analyzed

Complexity

Conditions 9
Paths 21

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 10.0551

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 18
c 1
b 0
f 0
nc 21
nop 3
dl 0
loc 33
ccs 13
cts 17
cp 0.7647
crap 10.0551
rs 8.0555
1
<?php
2
3
namespace roaresearch\yii2\roa;
4
5
/**
6
 * @author Angel (Faryshta) Guevara
7
 */
8
class ArrayHelper extends \yii\helpers\ArrayHelper
9
{
10
    /**
11
     * Normalizes an array to follow a 'field' => 'definition'
12
     * pairing.
13
     *
14
     * [
15
     *    'a',
16
     *    'b',
17
     *    'c' = 'full_c'
18
     *    'd' => fn () => $this->a + $this->b,
19
     * ]
20
     *
21
     * turns into
22
     *
23
     * [
24
     *    'a' => 'a',
25
     *    'b' => 'b',
26
     *    'c' = 'full_c'
27
     *    'd' => fn () => $this->a + $this->b,
28
     * ]
29
     *
30
     * @param array $fields
31
     * @return array
32
     */
33
    public static function normalize(array $fields): array
34
    {
35
        $result = [];
36
37
        foreach ($fields as $field => $definition) {
38
            if (is_int($field)) {
39
                $field = $definition;
40
            }
41
42
            $result[$field] = $definition;
43
        }
44
45
        return $result;
46
    }
47
48
    /**
49
     * @param array $fields fields to normalize
50
     * @param array $filters list of valid fields. It accept the wildcard '*'
51
     *   and will filter out any field denoted here with an '!' token. Example:
52
     *   '!name' will not allow the field 'name' to be included. If the list of
53
     *   valid fields is empty then all fields will be included except the
54
     *   ones not allowed.
55
     * @param ?Callable $callback can be used to process the field definition
56
     *   with signature `function (string $field, mixed $definition): mixed`
57
     *   where the return is the value to be associated to $field.
58
     * @return array filtered and normalized fields.
59
     * @see normalize
60
     */
61 9
    public static function normalizeFilter(
62
        array $fields,
63
        array $filters,
64
        ?Callable $callback = null
65
    ): array {
66 9
        $filterIn = $filterOut = [];
67 9
        foreach ($filters as $filter) {
68
            if (str_starts_with($filter, '!')) {
69
                $filterOut[] = substr($filter, 1);
70
            } else {
71
                $filterIn[] = $filter;
72
            }
73
        }
74
75 9
        $filterIn = static::rootFields($filterIn);
76 9
        $result = [];
77
78 9
        foreach ($fields as $field => $definition) {
79 9
            if (is_int($field)) {
80 7
                $field = $definition;
81
            }
82
83
            if (
84 9
                (empty($filterIn) || in_array($field, $filterIn))
85 9
                && !in_array($field, $filterOut)
86
            ) {
87 9
                $result[$field] = $callback
88 9
                    ? $callback($field, $definition)
89
                    : $definition;
90
            }
91
        }
92
93 9
        return $result;
94
    }
95
96
    /**
97
     * @param array $fields fields to normalize
98
     * @param array $filters list of the only valid fields. Does not accept
99
     *   wildcards and if empty then the returned list will be empty too.
100
     * @param ?Callable $callback can be used to process the field definition
101
     *   with signature `function (string $field, mixed $definition): mixed`
102
     *   where the return is the value to be associated to $field.
103
     * @return array filtered and normalized fields.
104
     * @see normalize
105
     */
106 9
    public static function normalizeStrict(
107
        array $fields,
108
        array $filters,
109
        ?Callable $callback = null
110
    ): array {
111 9
        if (empty($filters)) {
112 9
            return [];
113
        }
114 4
        $filters = static::rootFields($filters);
115
116 4
        $result = [];
117
118 4
        foreach ($fields as $field => $definition) {
119 4
            if (is_int($field)) {
120 4
                $field = $definition;
121
            }
122
123 4
            if (in_array($field, $filters)) {
124 4
                $result[$field] = $callback
125 4
                    ? $callback($field, $definition)
126
                    : $definition;
127
            }
128
        }
129
130 4
        return $result;
131
    }
132
133
    /**
134
     * List of fields requested to the root item. Example
135
     *
136
     * ```php
137
     * [
138
     *    'name',
139
     *    'shop.name',
140
     *    'shop.address',
141
     * ]
142
     * ```
143
     *
144
     * will return `['name', 'shop']`
145
     *
146
     * @param array $fields
147
     * @return array
148
     */
149 9
    public static function rootFields(array $fields): array
150
    {
151 9
        $result = [];
152
153 9
        foreach ($fields as $field) {
154 4
            $result[] = current(explode('.', $field, 2));
155
        }
156
157 9
        if (in_array('*', $result, true)) {
158
            return [];
159
        }
160
161 9
        return array_unique($result);
162
        
163
    }
164
165
    /**
166
     * List of fields requested to the $rootItem. Example
167
     *
168
     * ```php
169
     * [
170
     *    'name',
171
     *    'shop.name',
172
     *    'shop.address',
173
     * ]
174
     * ```
175
     *
176
     * will for $rootItem 'shop' will return `['name', 'address']`
177
     *
178
     * @param array $fields
179
     * @param string $rootItem
180
     * @return array
181
     */
182 4
    public static function fieldsFor(array $fields, string $rootField): array
183
    {
184 4
        $result = [];
185
186 4
        foreach ($fields as $field) {
187 4
            if (str_starts_with($field, "{$rootField}.")) {
188
                $result[] = substr($field, strlen($rootField) + 1);
189
            }
190
        }
191
192 4
        return array_unique($result);
193
    }
194
}
195