Completed
Push — master ( fb2597...95a931 )
by Viacheslav
04:33
created

JsonPointer::getByPointer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 2
crap 1
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 15
    public static function escapeSegment($key, $isURIFragmentId = false)
14
    {
15 15
        if ($isURIFragmentId) {
16 1
            return str_replace(array('%2F', '%7E'), array('~0', '~1'), urlencode($key));
17
        } else {
18 14
            return str_replace(array('~', '/'), array('~0', '~1'), $key);
19
        }
20
    }
21
22
    /**
23
     * @param string $path
24
     * @return string[]
25
     * @throws Exception
26
     */
27 91
    public static function splitPath($path)
28
    {
29 91
        $pathItems = explode('/', $path);
30 91
        $first = array_shift($pathItems);
31 91
        if ($first === '#') {
32 1
            return self::splitPathURIFragment($pathItems);
33
        } else {
34 91
            if ($first !== '') {
35
                throw new Exception('Path must start with "/": ' . $path);
36
            }
37 91
            return self::splitPathJsonString($pathItems);
38
        }
39
    }
40
41 1
    private static function splitPathURIFragment(array $pathItems)
42
    {
43 1
        $result = array();
44 1
        foreach ($pathItems as $key) {
45 1
            $key = str_replace(array('~1', '~0'), array('/', '~'), urldecode($key));
46 1
            $result[] = $key;
47
        }
48 1
        return $result;
49
    }
50
51 91
    private static function splitPathJsonString(array $pathItems)
52
    {
53 91
        $result = array();
54 91
        foreach ($pathItems as $key) {
55 87
            $key = str_replace(array('~1', '~0'), array('/', '~'), $key);
56 87
            $result[] = $key;
57
        }
58 91
        return $result;
59
    }
60
61
    /**
62
     * @param mixed $holder
63
     * @param string[] $pathItems
64
     * @param mixed $value
65
     * @param bool $recursively
66
     * @throws Exception
67
     */
68 65
    public static function add(&$holder, $pathItems, $value, $recursively = true)
69
    {
70 65
        $ref = &$holder;
71 65
        while (null !== $key = array_shift($pathItems)) {
72 61
            if ($ref instanceof \stdClass) {
73 42
                if (PHP_VERSION_ID < 71000 && '' === $key) {
74
                    throw new Exception('Empty property name is not supported by PHP <7.1',
75
                        Exception::EMPTY_PROPERTY_NAME_UNSUPPORTED);
76
                }
77
78 42
                $ref = &$ref->$key;
79
            } else { // null or array
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
80 39
                $intKey = filter_var($key, FILTER_VALIDATE_INT);
81 39
                if ($ref === null && (false === $intKey || $intKey !== 0)) {
82 12
                    $key = (string)$key;
83 12
                    if ($recursively) {
84 10
                        $ref = new \stdClass();
85 10
                        $ref = &$ref->{$key};
86
                    } else {
87 12
                        throw new Exception('Non-existent path');
88
                    }
89
                } else {
90 34
                    if ($recursively && $ref === null) $ref = array();
91 34
                    if ('-' === $key) {
92 4
                        $ref = &$ref[];
93
                    } else {
94 31
                        if (is_array($ref) && array_key_exists($key, $ref) && empty($pathItems)) {
95 5
                            array_splice($ref, $key, 0, array($value));
96
                        }
97 31
                        if (false === $intKey) {
98 2
                            throw new Exception('Invalid key for array operation');
99
                        }
100 29
                        if ($intKey > count($ref) && !$recursively) {
101 2
                            throw new Exception('Index is greater than number of items in array');
102 27
                        } elseif ($intKey < 0) {
103 1
                            throw new Exception('Negative index');
104
                        }
105
106 26
                        $ref = &$ref[$intKey];
107
                    }
108
                }
109
            }
110
        }
111 58
        $ref = $value;
112 58
    }
113
114 42
    private static function arrayKeyExists($key, array $a)
115
    {
116 42
        if (array_key_exists($key, $a)) {
117 38
            return true;
118
        }
119 7
        $key = (string)$key;
120 7
        foreach ($a as $k => $v) {
121 7
            if ((string)$k === $key) {
122 7
                return true;
123
            }
124
        }
125 7
        return false;
126
    }
127
128 31
    private static function arrayGet($key, array $a)
129
    {
130 31
        $key = (string)$key;
131 31
        foreach ($a as $k => $v) {
132 31
            if ((string)$k === $key) {
133 31
                return $v;
134
            }
135
        }
136
        return false;
137
    }
138
139
140
    /**
141
     * @param mixed $holder
142
     * @param string[] $pathItems
143
     * @return bool|mixed
144
     * @throws Exception
145
     */
146 43
    public static function get($holder, $pathItems)
147
    {
148 43
        $ref = $holder;
149 43
        while (null !== $key = array_shift($pathItems)) {
150 42
            if ($ref instanceof \stdClass) {
151 32
                if (PHP_VERSION_ID < 71000 && '' === $key) {
152
                    throw new Exception('Empty property name is not supported by PHP <7.1',
153
                        Exception::EMPTY_PROPERTY_NAME_UNSUPPORTED);
154
                }
155
156 32
                $vars = (array)$ref;
157 32
                if (self::arrayKeyExists($key, $vars)) {
158 31
                    $ref = self::arrayGet($key, $vars);
159
                } else {
160 32
                    throw new Exception('Key not found: ' . $key);
161
                }
162 21
            } elseif (is_array($ref)) {
163 21
                if (self::arrayKeyExists($key, $ref)) {
164 16
                    $ref = $ref[$key];
165
                } else {
166 21
                    throw new Exception('Key not found: ' . $key);
167
                }
168
            } else {
169
                throw new Exception('Key not found: ' . $key);
170
            }
171
        }
172 37
        return $ref;
173
    }
174
175
    /**
176
     * @param $holder
177
     * @param $pointer
178
     * @return bool|mixed
179
     * @throws Exception
180
     */
181 1
    public static function getByPointer($holder, $pointer)
182
    {
183 1
        return self::get($holder, self::splitPath($pointer));
184
    }
185
186
    /**
187
     * @param mixed $holder
188
     * @param string[] $pathItems
189
     * @return mixed
190
     * @throws Exception
191
     */
192 36
    public static function remove(&$holder, $pathItems)
193
    {
194 36
        $ref = &$holder;
195 36
        while (null !== $key = array_shift($pathItems)) {
196 35
            $parent = &$ref;
197 35
            $refKey = $key;
198 35
            if ($ref instanceof \stdClass) {
199 23
                if (property_exists($ref, $key)) {
200 22
                    $ref = &$ref->$key;
201
                } else {
202 23
                    throw new Exception('Key not found: ' . $key);
203
                }
204
            } else {
205 22
                if (array_key_exists($key, $ref)) {
206 19
                    $ref = &$ref[$key];
207
                } else {
208 3
                    throw new Exception('Key not found: ' . $key);
209
                }
210
            }
211
        }
212
213 32
        if (isset($parent) && isset($refKey)) {
214 31
            if ($parent instanceof \stdClass) {
215 19
                unset($parent->$refKey);
216
            } else {
217 15
                unset($parent[$refKey]);
218 15
                if ($refKey !== count($parent)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parent does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $refKey does not seem to be defined for all execution paths leading up to this point.
Loading history...
219 15
                    $parent = array_values($parent);
0 ignored issues
show
Unused Code introduced by
The assignment to $parent is dead and can be removed.
Loading history...
220
                }
221
            }
222
        }
223 32
        return $ref;
224
    }
225
}