Completed
Pull Request — master (#4)
by Matt
02:05
created

functions.php ➔ escape_pointer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 1
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace League\JsonReference;
4
5
use League\JsonReference\Pointer\NonExistentValue;
6
use Sabre\Uri;
7
8
/**
9
 * @param object|array $json
10
 *
11
 * @return Pointer
12
 */
13
function pointer(&$json)
14
{
15 24
    return new Pointer($json);
16
}
17
18
/**
19
 * Escape a JSON Pointer.
20
 *
21
 * @param  string $pointer
22
 * @return string
23
 */
24
function escape_pointer($pointer)
25
{
26
    return str_replace(['~', '/'], ['~0', '~1'], $pointer);
27
}
28
29
30
/**
31
 * Push a segment onto the given JSON Pointer.
32
 *
33
 * @param string   $pointer
34
 * @param string[] $segments
35
 *
36
 * @return string
37
 *
38
 */
39
function pointer_push($pointer, ...$segments)
40
{
41 50
    $segments = str_replace(['~', '/'], ['~0', '~1'], $segments);
42 50
    return ($pointer !== '/' ? $pointer : '') . '/' . implode('/', $segments);
43
}
44
45
/**
46
 * Removes the fragment from a reference.
47
 *
48
 * @param  string $ref
49
 * @return string
50
 */
51
function strip_fragment($ref)
52
{
53 46
    $fragment = Uri\parse($ref)['fragment'];
54
55 46
    return $fragment ? str_replace($fragment, '', $ref) : $ref;
56
}
57
58
/**
59
 * Check if the reference contains a fragment and resolve
60
 * the pointer.  Otherwise returns the original schema.
61
 *
62
 * @param  string $ref
63
 * @param  object $schema
64
 *
65
 * @return object
66
 */
67
function resolve_fragment($ref, $schema)
68
{
69 44
    $fragment = Uri\parse($ref)['fragment'];
70
71 44
    if (!is_internal_ref($ref) && is_string($fragment)) {
72 6
        return (new Pointer($schema))->get($fragment);
73
    }
74
75 40
    return $schema;
76
}
77
78
/**
79
 * @param string $keyword
80
 * @param mixed  $value
81
 *
82
 * @return bool
83
 */
84
function is_ref($keyword, $value)
85
{
86 50
    return $keyword === '$ref' && is_string($value);
87
}
88
89
/**
90
 * Determine if a reference is relative.
91
 * A reference is relative if it does not being with a prefix.
92
 *
93
 * @param string $ref
94
 *
95
 * @return bool
96
 */
97
function is_relative_ref($ref)
98
{
99 48
    return !preg_match('#^.+\:\/\/.*#', $ref);
100
}
101
102
/**
103
 * @param string $value
104
 *
105
 * @return bool
106
 */
107
function is_internal_ref($value)
108
{
109 62
    return is_string($value) && substr($value, 0, 1) === '#';
110
}
111
112
/**
113
 * Parse an external reference returning the prefix and path.
114
 *
115
 * @param string $ref
116
 *
117
 * @return array
118
 *
119
 * @throws \InvalidArgumentException
120
 */
121
function parse_external_ref($ref)
122
{
123 48
    if (is_relative_ref($ref)) {
124 2
        throw new \InvalidArgumentException(
125 2
            sprintf(
126
                'The path  "%s" was expected to be an external reference but is missing a prefix.  ' .
127 2
                'The schema path should start with a prefix i.e. "file://".',
128 1
                $ref
129 1
            )
130 1
        );
131
    }
132
133 46
    list($prefix, $path) = explode('://', $ref, 2);
134 46
    $path = rtrim(strip_fragment($path), '#');
135
136 46
    return [$prefix, $path];
137
}
138
139
/**
140
 * Resolve the given id against the parent scope and return the resolved URI.
141
 *
142
 * @param string $id          The id to resolve.  This should be a valid relative or absolute URI.
143
 * @param string $parentScope The parent scope to resolve against.  Should be a valid URI or empty.
144
 *
145
 * @return string
146
 */
147
function resolve_uri($id, $parentScope)
148
{
149
    // If there is no parent scope, there is nothing to resolve against.
150 38
    if ($parentScope === '') {
151 10
        return $id;
152
    }
153
154 30
    return Uri\resolve($parentScope, $id);
155
}
156
157
/**
158
 * Recursively iterates over each value in the schema passing them to the callback function.
159
 * If the callback function returns true the value is returned into the result array, keyed by a JSON Pointer.
160
 *
161
 * @param mixed    $schema
162
 * @param callable $callback
163
 * @param string   $pointer
164
 *
165
 * @return array
166
 */
167
function schema_extract($schema, callable $callback, $pointer = '')
168
{
169 52
    $matches = [];
170
171 52
    if ($schema instanceof Reference || (!is_array($schema) && !is_object($schema))) {
172 18
        return $matches;
173
    }
174
175 52
    foreach ($schema as $keyword => $value) {
176 26
        switch (true) {
177 52
            case is_object($value):
178 46
                $matches = array_merge($matches, schema_extract($value, $callback, pointer_push($pointer, $keyword)));
179 46
                break;
180 52
            case is_array($value):
181 22
                foreach ($value as $k => $v) {
182 22
                    if ($callback($k, $v)) {
183
                        $matches[pointer_push($pointer, $keyword)] = $v;
184
                    } else {
185 22
                        $matches = array_merge(
186 11
                            $matches,
187 22
                            schema_extract($v, $callback, pointer_push($pointer, $keyword, $k))
188 11
                        );
189
                    }
190 11
                }
191 22
                break;
192 52
            case $callback($keyword, $value):
193 50
                $matches[$pointer] = $value;
194 51
                break;
195
        }
196 26
    }
197
198 52
    return $matches;
199
}
200
201
/**
202
 * @param object $schema
203
 * @param object $resolvedRef
204
 * @param string $path
205
 *
206
 * @return object
207
 */
208
function merge_ref($schema, $resolvedRef, $path = '')
209
{
210 48
    if ($path === '') {
211 6
        pointer($schema)->remove('$ref');
212 6
        foreach ($resolvedRef as $prop => $value) {
213 4
            pointer($schema)->set($prop, $value);
214 2
        }
215 4
        return $schema;
216
    }
217
218 42
    $pointer = new Pointer($schema);
219 42
    if ($pointer->has($path)) {
220 42
        $pointer->set($path, $resolvedRef);
221 21
    }
222 42
    return $schema;
223
}
224