Reference::resolve()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 0
dl 0
loc 13
ccs 7
cts 7
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace League\JsonReference;
4
5
/**
6
 * A Reference object represents an internal $ref in a JSON object.
7
 * Because JSON references can be circular, in-lining the reference is
8
 * impossible.  This object can be substituted for the $ref instead,
9
 * allowing lazy resolution of the $ref when needed.
10
 */
11
final class Reference implements \JsonSerializable, \IteratorAggregate
12
{
13
    /**
14
     * @var \League\JsonReference\DereferencerInterface|null
15
     */
16
    private static $dereferencer;
17
18
    /**
19
     * @var string
20
     */
21
    private $ref;
22
23
    /**
24
     * @var string
25
     */
26
    private $scope;
27
28
    /**
29
     * @var object|null
30
     */
31
    private $schema;
32
33
    /**
34
     * @var mixed
35
     */
36
    private $resolved;
37
38
    /**
39
     * @param string $ref
40
     * @param string $scope
41
     * @param null   $schema
42
     */
43 62
    public function __construct($ref, $scope = '', $schema = null)
44
    {
45 62
        $this->ref        = $ref;
46 62
        $this->scope      = $scope;
47 62
        $this->schema     = $schema;
48 62
    }
49
50
    /**
51
     * Specify data which should be serialized to JSON.
52
     * Because a reference can be circular, references are always
53
     * re-serialized as the reference property instead of attempting
54
     * to inline the data.
55
     *
56
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
57
     *
58
     * @return mixed data which can be serialized by <b>json_encode</b>,
59
     * which is a value of any type other than a resource.
60
     */
61 16
    public function jsonSerialize()
62
    {
63 16
        return $this->dereferencer()->getReferenceSerializer()->serialize($this);
64
    }
65
66
    /**
67
     * Resolve the reference and return the data.
68
     *
69
     * @return mixed
70
     */
71 50
    public function resolve()
72
    {
73 50
        if (isset($this->resolved)) {
74 10
            return $this->resolved;
75
        }
76
77 50
        $pointer = new Pointer($this->schema);
0 ignored issues
show
Bug introduced by
It seems like $this->schema can also be of type null; however, League\JsonReference\Pointer::__construct() does only seem to accept object|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78 50
        if (is_internal_ref($this->ref) && $pointer->has($this->ref)) {
79 34
            return $this->resolved = $pointer->get($this->ref);
80
        }
81
82 16
        return $this->dereferencer()->dereference(resolve_uri($this->ref, $this->scope));
83
    }
84
85
    /**
86
     * Proxies property access to the underlying schema.
87
     *
88
     * @param  string $property
89
     *
90
     * @return mixed
91
     *
92
     * @throws \InvalidArgumentException
93
     */
94 18
    public function __get($property)
95
    {
96 18
        $schema  = $this->resolve();
97 18
        $pointer = pointer($schema);
98 18
        if ($pointer->has($property)) {
99 16
            return $pointer->get($property);
100
        }
101
102 2
        throw new \InvalidArgumentException(sprintf('Unknown property "%s"', $property));
103
    }
104
105
    /**
106
     * @param string $property
107
     *
108
     * @return mixed
109
     *
110
     * @throws \InvalidArgumentException
111
     */
112
    public function get($property)
113
    {
114
        if (!$this->has($property)) {
115
            throw new \InvalidArgumentException(sprintf('Unknown property "%s"', $property));
116
        }
117
118
        $schema = $this->resolve();
119
        return pointer($schema)->get($property);
120
    }
121
122
    /**
123
     * @param string $property
124
     *
125
     * @return bool
126
     */
127
    public function has($property)
128
    {
129
        $schema = $this->resolve();
130
        return pointer($schema)->has($property);
131
    }
132
133
    /**
134
     * @return string
135
     */
136 10
    public function getRef()
137
    {
138 10
        return $this->ref;
139
    }
140
141
    /**
142
     * @return string
143
     */
144
    public function getScope()
145
    {
146
        return $this->scope;
147
    }
148
149
    /**
150
     * @return object|null
151
     */
152
    public function getSchema()
153
    {
154
        return $this->schema;
155
    }
156
157
    /**
158
     * Retrieve an external iterator
159
     * @link  http://php.net/manual/en/iteratoraggregate.getiterator.php
160
     * @return \Traversable An instance of an object implementing <b>Iterator</b> or
161
     * <b>Traversable</b>
162
     * @since 5.0.0
163
     */
164 12
    public function getIterator()
165
    {
166
        // Recursively resolve until we hit a real schema
167
        //because you can't use get_object_vars on a reference.
168 12
        $schema = $this->resolve();
169 10
        while ($schema instanceof Reference) {
170
            $schema = $schema->resolve();
171
        }
172
173 10
        if (!is_object($schema) && !is_array($schema)) {
174 2
            throw new \InvalidArgumentException(
175 2
                sprintf('Expected an object or array, got "%s"', gettype($schema))
176 1
            );
177
        }
178
179 8
        return new \ArrayIterator(is_object($schema) ? get_object_vars($schema) : $schema);
180
    }
181
182
    /**
183
     * @param \League\JsonReference\DereferencerInterface|null $dereferencer
184
     */
185 54
    public static function setDereferencerInstance(DereferencerInterface $dereferencer = null)
186
    {
187 54
        self::$dereferencer = $dereferencer;
188 54
    }
189
190
    /**
191
     * @return \League\JsonReference\DereferencerInterface
192
     *
193
     * @throws \RuntimeException
194
     */
195 30
    private function dereferencer()
196
    {
197 30
        if (!self::$dereferencer) {
198
            throw new \RuntimeException(
199
                sprintf('The reference %s cannot be resolved or serialized without a Dereferencer.', $this->ref)
200
            );
201
        }
202
203 30
        return self::$dereferencer;
204
    }
205
}
206