Completed
Push — master ( aeb11c...f98da5 )
by Adrian
02:32
created

Arr::getBySelector()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 30
ccs 21
cts 21
cp 1
rs 6.7272
cc 7
eloc 17
nc 9
nop 2
crap 7
1
<?php
2
3
namespace Sirius\Validation\Util;
4
5
class Arr
6
{
7
8
    /**
9
     * Constant that represents the root of an array
10
     */
11
    const PATH_ROOT = '/';
12
13
    /**
14
     * @param $selector
15
     *
16
     * @return array
17
     */
18 36
    protected static function getSelectorParts($selector)
19
    {
20 36
        $firstOpen = strpos($selector, '[');
21 36
        if ($firstOpen === false) {
22 36
            return array( $selector, '' );
23
        }
24 10
        $firstClose  = strpos($selector, ']');
25 10
        $container   = substr($selector, 0, $firstOpen);
26 10
        $subselector = substr($selector, $firstOpen + 1, $firstClose - $firstOpen - 1) . substr(
27 10
                $selector,
28
                $firstClose + 1
29 10
            );
30
31 10
        return array( $container, $subselector );
32
    }
33
34
    /**
35
     * Retrieves an element from an array via its path
36
     * Path examples:
37
     *        key
38
     *        key[subkey]
39
     *        key[0][subkey]
40
     *
41
     * @param  array $array
42
     * @param  string $path
43
     *
44
     * @return mixed
45
     */
46 37
    public static function getByPath($array, $path = self::PATH_ROOT)
47
    {
48 37
        $path = trim($path);
49 37
        if ( ! $path || $path == self::PATH_ROOT) {
50 1
            return $array;
51
        }
52
        // fix the path in case it was provided as `[item][subitem]`
53 36
        if (strpos($path, '[') === 0) {
54 3
            $path = preg_replace('/]/', '', ltrim($path, '['), 1);
55 3
        }
56
57 36
        list($container, $subpath) = self::getSelectorParts($path);
58 36
        if ($subpath === '') {
59 36
            return array_key_exists($container, $array) ? $array[$container] : null;
60
        }
61
62 10
        return array_key_exists($container, $array) ? self::getByPath($array[$container], $subpath) : null;
63
    }
64
65
    /**
66
     * Set values in the array by selector
67
     *
68
     * @example
69
     * Arr::setBySelector($data, 'email', '[email protected]');
70
     * Arr::setBySelector($data, 'addresses[0][line]', null);
71
     * Arr::setBySelector($data, 'addresses[*][line]', null);
72
     *
73
     * @param  array $array
74
     * @param  string $selector
75
     * @param  mixed $value
76
     * @param  bool $overwrite true if the $value should overwrite the existing value
77
     *
78
     * @return array
79
     */
80 3
    public static function setBySelector($array, $selector, $value, $overwrite = false)
81
    {
82
        // make sure the array is an array in case we got here through a subsequent call
83
        // so arraySetElementBySelector(array(), 'item[subitem]', 'value');
84
        // will call arraySetElementBySelector(null, 'subitem', 'value');
85 3
        if ( ! is_array($array)) {
86 1
            $array = array();
87 1
        }
88 3
        list($container, $subselector) = self::getSelectorParts($selector);
89 3
        if ( ! $subselector) {
90 3
            if ($container !== '*') {
91 3
                if ($overwrite === true || ! array_key_exists($container, $array)) {
92 2
                    $array[$container] = $value;
93 2
                }
94 3
            }
95
96 3
            return $array;
97
        }
98
99
        // if we have a subselector the $array[$container] must be an array
100 1
        if ($container !== '*' && ! array_key_exists($container, $array)) {
101 1
            $array[$container] = array();
102 1
        }
103
        // we got here through something like *[subitem]
104 1
        if ($container === '*') {
105 1
            foreach ($array as $key => $v) {
106 1
                $array[$key] = self::setBySelector($array[$key], $subselector, $value, $overwrite);
107 1
            }
108 1
        } else {
109 1
            $array[$container] = self::setBySelector($array[$container], $subselector, $value, $overwrite);
110
        }
111
112 1
        return $array;
113
    }
114
115
    /**
116
     * Get values in the array by selector
117
     *
118
     * @example
119
     * Arr::getBySelector($data, 'email');
120
     * Arr::getBySelector($data, 'addresses[0][line]');
121
     * Arr::getBySelector($data, 'addresses[*][line]');
122
     *
123
     * @param $array
124
     * @param $selector
125
     *
126
     * @return array
127
     */
128 18
    public static function getBySelector($array, $selector)
129
    {
130 18
        if (strpos($selector, '[*]') === false) {
131
            return array(
132 14
                $selector => self::getByPath($array, $selector)
133 14
            );
134
        }
135 5
        $result = array();
136 5
        list($preffix, $suffix) = explode('[*]', $selector, 2);
137
138 5
        $base = self::getByPath($array, $preffix);
139 5
        if ( ! is_array($base)) {
140 1
            $base = array();
141 1
        }
142
        // we don't have a suffix, the selector was something like path[subpath][*]
143 5
        if ( ! $suffix) {
144 2
            foreach ($base as $k => $v) {
145 1
                $result["{$preffix}[{$k}]"] = $v;
146 2
            }
147
            // we have a suffix, the selector was something like path[*][item]
148 2
        } else {
149 3
            foreach ($base as $itemKey => $itemValue) {
150 3
                if (is_array($itemValue)) {
151 3
                    $result["{$preffix}[{$itemKey}]{$suffix}"] = self::getByPath($itemValue, $suffix);
152 3
                }
153 3
            }
154
        }
155
156 5
        return $result;
157
    }
158
}
159