Dereferencer::isReference()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the OpenapiBundle package.
7
 *
8
 * (c) Niels Nijens <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Nijens\OpenapiBundle\Json;
15
16
use League\Uri\Uri;
17
use Nijens\OpenapiBundle\Json\Loader\LoaderInterface;
18
use stdClass;
19
20
/**
21
 * Dereferences a JSON schema by replacing $ref JSON pointers with a {@see Reference} value-object.
22
 *
23
 * @author Niels Nijens <[email protected]>
24
 */
25
class Dereferencer implements DereferencerInterface
26
{
27
    /**
28
     * @var JsonPointerInterface
29
     */
30
    private $jsonPointer;
31
32
    /**
33
     * @var LoaderInterface
34
     */
35
    private $loader;
36
37
    /**
38
     * Constructs a new {@see Dereferencer} instance.
39
     */
40
    public function __construct(JsonPointerInterface $jsonPointer, LoaderInterface $loader)
41
    {
42
        $this->jsonPointer = $jsonPointer;
43
        $this->loader = $loader;
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function dereference(stdClass $jsonSchema): stdClass
50
    {
51
        $jsonPointer = $this->jsonPointer->withJson($jsonSchema);
52
53
        $references = $this->searchReferences($jsonSchema);
54
        foreach ($references as $referenceLocationPointer => $referencePointer) {
55
            $reference = new Reference($referencePointer, $jsonSchema);
56
            if ($this->isExternalReference($referencePointer)) {
57
                $externalFile = (string) Uri::createFromString($referencePointer)->withFragment(null);
58
                $externalReferencePointer = '#'.Uri::createFromString($referencePointer)->getFragment();
59
60
                $externalJsonSchema = $this->dereference($this->loader->load($externalFile));
61
62
                $reference = new Reference($externalReferencePointer, $externalJsonSchema);
63
            }
64
65
            $schemaReference = &$jsonPointer->getByReference($referenceLocationPointer);
66
            $schemaReference = $reference;
67
        }
68
69
        return $jsonSchema;
70
    }
71
72
    /**
73
     * Returns the $ref JSON pointers within the provided JSON schema.
74
     */
75
    private function searchReferences(stdClass $jsonSchema, string $jsonPointer = '#'): array
76
    {
77
        $references = [];
78
        foreach ($jsonSchema as $key => $value) {
79
            if (is_object($value)) {
80
                $references = array_merge(
81
                    $references,
82
                    $this->searchReferences(
83
                        $value,
84
                        $this->jsonPointer->appendSegmentsToPointer($jsonPointer, $key)
85
                    )
86
                );
87
88
                continue;
89
            }
90
91
            if (is_array($value)) {
92
                foreach ($value as $arrayKey => $arrayValue) {
93
                    if (is_object($arrayValue) === false) {
94
                        continue;
95
                    }
96
97
                    $references = array_merge(
98
                        $references,
99
                        $this->searchReferences(
100
                            $arrayValue,
101
                            $this->jsonPointer->appendSegmentsToPointer($jsonPointer, $key, (string) $arrayKey)
102
                        )
103
                    );
104
                }
105
106
                continue;
107
            }
108
109
            if ($this->isReference($key, $value)) {
110
                $references[$jsonPointer] = $value;
111
            }
112
        }
113
114
        return $references;
115
    }
116
117
    /**
118
     * Returns true when the provided JSON key and value is a JSON reference.
119
     *
120
     * @param mixed $key
121
     * @param mixed $value
122
     */
123
    private function isReference($key, $value): bool
124
    {
125
        return $key === '$ref' && is_string($value);
126
    }
127
128
    /**
129
     * Returns true when the provided JSON key and value is an internal JSON reference.
130
     */
131
    private function isInternalReference(string $jsonPointer): bool
132
    {
133
        return substr($jsonPointer, 0, 1) === '#';
134
    }
135
136
    /**
137
     * Returns true when the provided JSON key and value is an external JSON reference.
138
     */
139
    private function isExternalReference(string $jsonPointer): bool
140
    {
141
        return $this->isInternalReference($jsonPointer) === false;
142
    }
143
}
144