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

JsonPointer::splitPath()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5.009

Importance

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