File: JsonSchemaReferenceResolver.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (79 lines) | stat: -rw-r--r-- 2,498 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php

namespace MediaWiki\Settings\Source;

use Error;
use InvalidArgumentException;

/**
 * Utility for resolving references ($ref) in JSON-schemas
 * and building a collection of the referenced definitions.
 *
 * @since 1.42
 * @unstable
 */
class JsonSchemaReferenceResolver {
	/**
	 * Returns a URI relative to a JSON-schema document
	 * for a given definition name
	 *
	 * @param array $schema A $ref sub-schema
	 * @return string Definition relative URI
	 */
	public static function normalizeRef( array $schema ): string {
		return '#/$defs/' . self::getDefinitionName( $schema );
	}

	/**
	 * Destructures and validates a JSON-schema "$ref" definition of the
	 * form [ "class" => SomePHPClass:class, "field" => "someExistingPublicConsInTheClass" ]
	 *
	 * @param array $schema A $ref sub-schema
	 * @return array An array with the class name as the first element, and the field name as the second.
	 */
	private static function unpackRef( array $schema ): array {
		$className = $schema['class'];
		$field = $schema['field'];
		if ( !$className || !$field ) {
			throw new InvalidArgumentException( 'The schema $ref must have "class" and "field" defined.' );
		}
		return [
			$className,
			$field
		];
	}

	/**
	 * Builds a definition name based on the specified "$ref" definition
	 *
	 * @param array $schema A $ref sub-schema
	 * @return string A definition name using both the name of the class and the field
	 */
	public static function getDefinitionName( array $schema ): string {
		[ $className, $field ] = self::unpackRef( $schema );
		// Avoid using "\" or "/" in the definition name as they are interpreted as fragment
		// separators in the URI and make consumers of the schema unable to resolve a document
		// relative schema. Use "." as the word separator for the namespace, resulting in
		// eg: SomeExtension.Namespace.MyClass::MyConstant
		return str_replace( "\\", '.', $className ) . '::' . $field;
	}

	/**
	 * Returns the value of a given reference "$ref".
	 *
	 * @param array $schema A $ref sub-schema
	 * @return array The value of the class field referenced by the definition
	 */
	public static function resolveRef( array $schema, string $rootClass ): array {
		[ $className, $fieldName ] = self::unpackRef( $schema );
		try {
			$value = constant( "$className::$fieldName" );
		} catch ( Error $e ) {
			throw new RefNotFoundException(
				"Failed resolving reference $fieldName in $className. Root schema location: $rootClass"
			);
		}
		return $value;
	}

}