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

JsonPointer::get()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6.0131

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 13
cts 14
cp 0.9286
rs 8.6737
c 0
b 0
f 0
cc 6
eloc 16
nc 6
nop 2
crap 6.0131
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
        $pp = $pathItems;
0 ignored issues
show
Unused Code introduced by
The assignment to $pp is dead and can be removed.
Loading history...
59 24
        $ref = &$holder;
60 24
        while (null !== $key = array_shift($pathItems)) {
61 22
            if ($ref instanceof \stdClass) {
62 22
                $ref = &$ref->$key;
63 17
            } elseif ($ref === null
64 17
                && !is_int($key)
65 17
                && false === filter_var($key, FILTER_VALIDATE_INT)
66
            ) {
67 13
                $key = (string)$key;
68 13
                if ($recursively) {
69 11
                    $ref = new \stdClass();
70 11
                    $ref = &$ref->{$key};
71
                } else {
72 13
                    throw new Exception('Non-existent path');
73
                }
74
            } else {
75 12
                if ($recursively && $ref === null) {
76 8
                    $ref = array();
77
                }
78
79 12
                if ('-' === $key) {
80 1
                    $ref = &$ref[];
81
                } else {
82 11
                    $key = (int)$key;
83 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...
84 3
                        array_splice($ref, $key, 0, array($value));
85
                    }
86 11
                    $ref = &$ref[$key];
87
                }
88
            }
89
        }
90 22
        $ref = $value;
91 22
    }
92
93 11
    private static function arrayKeyExists($key, array $a)
94
    {
95 11
        if (array_key_exists($key, $a)) {
96 11
            return true;
97
        }
98 1
        $key = (string)$key;
99 1
        foreach ($a as $k => $v) {
100 1
            if ((string)$k === $key) {
101 1
                return true;
102
            }
103
        }
104 1
        return false;
105
    }
106
107 11
    private static function arrayGet($key, array $a)
108
    {
109 11
        $key = (string)$key;
110 11
        foreach ($a as $k => $v) {
111 11
            if ((string)$k === $key) {
112 11
                return $v;
113
            }
114
        }
115
        return false;
116
    }
117
118
119
    /**
120
     * @param mixed $holder
121
     * @param string[] $pathItems
122
     * @return bool|mixed
123
     * @throws Exception
124
     */
125 11
    public static function get($holder, $pathItems)
126
    {
127 11
        $ref = $holder;
128 11
        while (null !== $key = array_shift($pathItems)) {
129 11
            if ($ref instanceof \stdClass) {
130 11
                $vars = (array)$ref;
131 11
                if (self::arrayKeyExists($key, $vars)) {
132 11
                    $ref = self::arrayGet($key, $vars);
133
                } else {
134 11
                    throw new Exception('Key not found: ' . $key);
135
                }
136 5
            } elseif (is_array($ref)) {
137 5
                if (self::arrayKeyExists($key, $ref)) {
138 5
                    $ref = $ref[$key];
139
                } else {
140 5
                    throw new Exception('Key not found: ' . $key);
141
                }
142
            } else {
143
                throw new Exception('Key not found: ' . $key);
144
            }
145
        }
146 11
        return $ref;
147
    }
148
149
    /**
150
     * @param mixed $holder
151
     * @param string[] $pathItems
152
     * @return mixed
153
     * @throws Exception
154
     */
155 10
    public static function remove(&$holder, $pathItems)
156
    {
157 10
        $ref = &$holder;
158 10
        while (null !== $key = array_shift($pathItems)) {
159 10
            $parent = &$ref;
160 10
            $refKey = $key;
161 10
            if ($ref instanceof \stdClass) {
162 10
                if (property_exists($ref, $key)) {
163 9
                    $ref = &$ref->$key;
164
                } else {
165 10
                    throw new Exception('Key not found: ' . $key);
166
                }
167
            } else {
168 5
                if (array_key_exists($key, $ref)) {
169 5
                    $ref = &$ref[$key];
170
                } else {
171
                    throw new Exception('Key not found: ' . $key);
172
                }
173
            }
174
        }
175
176 9
        if (isset($parent) && isset($refKey)) {
177 9
            if ($parent instanceof \stdClass) {
178 7
                unset($parent->$refKey);
179
            } else {
180 4
                unset($parent[$refKey]);
181 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...
182
            }
183
        }
184 9
        return $ref;
185
    }
186
}