Passed
Pull Request — master (#3)
by Viacheslav
01:57
created

JsonPointer::arrayKeyExists()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 8
cts 8
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 4
nop 2
crap 4
1
<?php
2
3
namespace Swaggest\JsonDiff;
4
5
6
class JsonPointer
7
{
8
    /**
9
     * @param string $key
10
     * @param bool $isURIFragmentId
11
     * @return string
12
     */
13 11
    public static function escapeSegment($key, $isURIFragmentId = false)
14
    {
15 11
        if ($isURIFragmentId) {
16 1
            return str_replace(array('%2F', '%7E'), array('~0', '~1'), urlencode($key));
17
        } else {
18 10
            return str_replace(array('~', '/'), array('~0', '~1'), $key);
19
        }
20
    }
21
22
    /**
23
     * @param string $path
24
     * @return string[]
25
     * @throws Exception
26
     */
27 22
    public static function splitPath($path)
28
    {
29 22
        $pathItems = explode('/', $path);
30 22
        $first = array_shift($pathItems);
31 22
        $result = array();
32 22
        if ($first === '#') {
33 1
            foreach ($pathItems as $key) {
34 1
                $key = str_replace(array('~1', '~0'), array('/', '~'), urldecode($key));
35 1
                $result[] = $key;
36
            }
37
        } else {
38 22
            if ($first !== '') {
39
                throw new Exception('Path must start with "/": ' . $path);
40
            }
41 22
            foreach ($pathItems as $key) {
42 22
                $key = str_replace(array('~1', '~0'), array('/', '~'), $key);
43 22
                $result[] = $key;
44
            }
45
        }
46 22
        return $result;
47
    }
48
49
    /**
50
     * @param mixed $holder
51
     * @param string[] $pathItems
52
     * @param mixed $value
53
     * @param bool $recursively
54
     * @throws Exception
55
     */
56 24
    public static function add(&$holder, $pathItems, $value, $recursively = true)
57
    {
58 24
        $ref = &$holder;
59 24
        while (null !== $key = array_shift($pathItems)) {
60 22
            if ($ref instanceof \stdClass) {
61 22
                $ref = &$ref->$key;
62 17
            } elseif ($ref === null
63 17
                && !is_int($key)
64 17
                && false === filter_var($key, FILTER_VALIDATE_INT)
65
            ) {
66 13
                $key = (string)$key;
67 13
                if ($recursively) {
68 11
                    $ref = new \stdClass();
69 11
                    $ref = &$ref->{$key};
70
                } else {
71 13
                    throw new Exception('Non-existent path');
72
                }
73
            } else {
74 12
                if ($recursively && $ref === null) {
75 8
                    $ref = array();
76
                }
77
78 12
                if ('-' === $key) {
79 1
                    $ref = &$ref[];
80
                } else {
81 11
                    $key = (int)$key;
82 11
                    if (is_array($ref) && array_key_exists($key, $ref) && !$pathItems) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $pathItems of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
83 3
                        array_splice($ref, $key, 0, array($value));
84
                    }
85 11
                    $ref = &$ref[$key];
86
                }
87
            }
88
        }
89 22
        $ref = $value;
90 22
    }
91
92 11
    private static function arrayKeyExists($key, array $a)
93
    {
94 11
        if (array_key_exists($key, $a)) {
95 11
            return true;
96
        }
97 1
        $key = (string)$key;
98 1
        foreach ($a as $k => $v) {
99 1
            if ((string)$k === $key) {
100 1
                return true;
101
            }
102
        }
103 1
        return false;
104
    }
105
106 11
    private static function arrayGet($key, array $a)
107
    {
108 11
        $key = (string)$key;
109 11
        foreach ($a as $k => $v) {
110 11
            if ((string)$k === $key) {
111 11
                return $v;
112
            }
113
        }
114
        return false;
115
    }
116
117
118
    /**
119
     * @param mixed $holder
120
     * @param string[] $pathItems
121
     * @return bool|mixed
122
     * @throws Exception
123
     */
124 11
    public static function get($holder, $pathItems)
125
    {
126 11
        $ref = $holder;
127 11
        while (null !== $key = array_shift($pathItems)) {
128 11
            if ($ref instanceof \stdClass) {
129 11
                $vars = (array)$ref;
130 11
                if (self::arrayKeyExists($key, $vars)) {
131 11
                    $ref = self::arrayGet($key, $vars);
132
                } else {
133 11
                    throw new Exception('Key not found: ' . $key);
134
                }
135 5
            } elseif (is_array($ref)) {
136 5
                if (self::arrayKeyExists($key, $ref)) {
137 5
                    $ref = $ref[$key];
138
                } else {
139 5
                    throw new Exception('Key not found: ' . $key);
140
                }
141
            } else {
142
                throw new Exception('Key not found: ' . $key);
143
            }
144
        }
145 11
        return $ref;
146
    }
147
148
    /**
149
     * @param mixed $holder
150
     * @param string[] $pathItems
151
     * @return mixed
152
     * @throws Exception
153
     */
154 10
    public static function remove(&$holder, $pathItems)
155
    {
156 10
        $ref = &$holder;
157 10
        while (null !== $key = array_shift($pathItems)) {
158 10
            $parent = &$ref;
159 10
            $refKey = $key;
160 10
            if ($ref instanceof \stdClass) {
161 10
                if (property_exists($ref, $key)) {
162 9
                    $ref = &$ref->$key;
163
                } else {
164 10
                    throw new Exception('Key not found: ' . $key);
165
                }
166
            } else {
167 5
                if (array_key_exists($key, $ref)) {
168 5
                    $ref = &$ref[$key];
169
                } else {
170
                    throw new Exception('Key not found: ' . $key);
171
                }
172
            }
173
        }
174
175 9
        if (isset($parent) && isset($refKey)) {
176 9
            if ($parent instanceof \stdClass) {
177 7
                unset($parent->$refKey);
178
            } else {
179 4
                unset($parent[$refKey]);
180 4
                $parent = array_values($parent);
0 ignored issues
show
Unused Code introduced by
The assignment to $parent is dead and can be removed.
Loading history...
181
            }
182
        }
183 9
        return $ref;
184
    }
185
}