@@ -45,7 +45,7 @@ public function getUriResolver()
4545 /**
4646 * {@inheritdoc}
4747 */
48- public function addSchema ($ id , $ schema = null )
48+ public function addSchema (string $ id , $ schema = null ): void
4949 {
5050 if (is_null ($ schema ) && $ id !== self ::INTERNAL_PROVIDED_SCHEMA_URI ) {
5151 // if the schema was user-provided to Validator and is still null, then assume this is
@@ -62,14 +62,16 @@ public function addSchema($id, $schema = null)
6262 // workaround for bug in draft-03 & draft-04 meta-schemas (id & $ref defined with incorrect format)
6363 // see https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/177#issuecomment-293051367
6464 if (is_object ($ schema ) && property_exists ($ schema , 'id ' )) {
65- if ($ schema ->id == 'http://json-schema.org/draft-04/schema# ' ) {
65+ if ($ schema ->id === 'http://json-schema.org/draft-04/schema# ' ) {
6666 $ schema ->properties ->id ->format = 'uri-reference ' ;
67- } elseif ($ schema ->id == 'http://json-schema.org/draft-03/schema# ' ) {
67+ } elseif ($ schema ->id === 'http://json-schema.org/draft-03/schema# ' ) {
6868 $ schema ->properties ->id ->format = 'uri-reference ' ;
6969 $ schema ->properties ->{'$ref ' }->format = 'uri-reference ' ;
7070 }
7171 }
7272
73+ $ this ->scanForSubschemas ($ schema , $ id );
74+
7375 // resolve references
7476 $ this ->expandRefs ($ schema , $ id );
7577
@@ -79,39 +81,44 @@ public function addSchema($id, $schema = null)
7981 /**
8082 * Recursively resolve all references against the provided base
8183 *
82- * @param mixed $schema
83- * @param string $base
84+ * @param mixed $schema
8485 */
85- private function expandRefs (&$ schema , $ base = null )
86+ private function expandRefs (&$ schema , ? string $ parentId = null ): void
8687 {
8788 if (!is_object ($ schema )) {
8889 if (is_array ($ schema )) {
8990 foreach ($ schema as &$ member ) {
90- $ this ->expandRefs ($ member , $ base );
91+ $ this ->expandRefs ($ member , $ parentId );
9192 }
9293 }
9394
9495 return ;
9596 }
9697
97- if (property_exists ($ schema , 'id ' ) && is_string ($ schema ->id ) && $ base != $ schema ->id ) {
98- $ base = $ this ->uriResolver ->resolve ($ schema ->id , $ base );
99- }
100-
10198 if (property_exists ($ schema , '$ref ' ) && is_string ($ schema ->{'$ref ' })) {
102- $ refPointer = new JsonPointer ($ this ->uriResolver ->resolve ($ schema ->{'$ref ' }, $ base ));
99+ $ refPointer = new JsonPointer ($ this ->uriResolver ->resolve ($ schema ->{'$ref ' }, $ parentId ));
103100 $ schema ->{'$ref ' } = (string ) $ refPointer ;
104101 }
105102
106- foreach ($ schema as &$ member ) {
107- $ this ->expandRefs ($ member , $ base );
103+ foreach ($ schema as $ propertyName => &$ member ) {
104+ if (in_array ($ propertyName , ['enum ' , 'const ' ])) {
105+ // Enum and const don't allow $ref as a keyword, see https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/445
106+ continue ;
107+ }
108+
109+ $ childId = $ parentId ;
110+ if (property_exists ($ schema , 'id ' ) && is_string ($ schema ->id ) && $ childId !== $ schema ->id ) {
111+ $ childId = $ this ->uriResolver ->resolve ($ schema ->id , $ childId );
112+ }
113+
114+ $ this ->expandRefs ($ member , $ childId );
108115 }
109116 }
110117
111118 /**
112119 * {@inheritdoc}
113120 */
114- public function getSchema ($ id )
121+ public function getSchema (string $ id )
115122 {
116123 if (!array_key_exists ($ id , $ this ->schemas )) {
117124 $ this ->addSchema ($ id );
@@ -123,7 +130,7 @@ public function getSchema($id)
123130 /**
124131 * {@inheritdoc}
125132 */
126- public function resolveRef ($ ref , $ resolveStack = [])
133+ public function resolveRef (string $ ref , $ resolveStack = [])
127134 {
128135 $ jsonPointer = new JsonPointer ($ ref );
129136
@@ -174,4 +181,32 @@ public function resolveRefSchema($refSchema, $resolveStack = [])
174181
175182 return $ refSchema ;
176183 }
184+
185+ /**
186+ * @param mixed $schema
187+ */
188+ private function scanForSubschemas ($ schema , string $ parentId ): void
189+ {
190+ if (!$ schema instanceof \stdClass && !is_array ($ schema )) {
191+ return ;
192+ }
193+
194+ foreach ($ schema as $ propertyName => $ potentialSubSchema ) {
195+ if (!is_object ($ potentialSubSchema )) {
196+ continue ;
197+ }
198+
199+ if (property_exists ($ potentialSubSchema , 'id ' ) && is_string ($ potentialSubSchema ->id ) && property_exists ($ potentialSubSchema , 'type ' )) {
200+ // Enum and const don't allow id as a keyword, see https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/471
201+ if (in_array ($ propertyName , ['enum ' , 'const ' ])) {
202+ continue ;
203+ }
204+
205+ // Found sub schema
206+ $ this ->addSchema ($ this ->uriResolver ->resolve ($ potentialSubSchema ->id , $ parentId ), $ potentialSubSchema );
207+ }
208+
209+ $ this ->scanForSubschemas ($ potentialSubSchema , $ parentId );
210+ }
211+ }
177212}
0 commit comments