functions.php ➔ schema_extract()   D
last analyzed

Complexity

Conditions 10
Paths 8

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 10.1728

Importance

Changes 0
Metric Value
cc 10
eloc 22
nc 8
nop 3
dl 0
loc 33
ccs 22
cts 25
cp 0.88
crap 10.1728
rs 4.8196
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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