Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
94.74% |
36 / 38 |
|
75.00% |
6 / 8 |
CRAP | |
0.00% |
0 / 1 |
JsonSchemaValidator | |
94.74% |
36 / 38 |
|
75.00% |
6 / 8 |
15.03 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
areSchemasSupported | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSchemaBuilder | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validateStrictly | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validatePermissively | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validate | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
5 | |||
getSchemaVersion | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSchemaIterator | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\CommunityConfiguration\Validation; |
4 | |
5 | use IBufferingStatsdDataFactory; |
6 | use InvalidArgumentException; |
7 | use Iterator; |
8 | use JsonSchema\Validator; |
9 | use MediaWiki\Extension\CommunityConfiguration\Schema\JsonSchema; |
10 | use MediaWiki\Extension\CommunityConfiguration\Schema\JsonSchemaBuilder; |
11 | use MediaWiki\Extension\CommunityConfiguration\Schema\JsonSchemaIterator; |
12 | use MediaWiki\Extension\CommunityConfiguration\Schema\JsonSchemaReader; |
13 | use MediaWiki\Extension\CommunityConfiguration\Schema\SchemaBuilder; |
14 | |
15 | /** |
16 | * JSON Schema validator. |
17 | */ |
18 | class JsonSchemaValidator implements IValidator { |
19 | |
20 | private JsonSchemaReader $jsonSchema; |
21 | private JsonSchemaBuilder $jsonSchemaBuilder; |
22 | private Iterator $jsonSchemaIterator; |
23 | private IBufferingStatsdDataFactory $statsdDataFactory; |
24 | |
25 | /** |
26 | * @param JsonSchema|string $classNameOrClassInstance JsonSchema derived class name (instance only allowed in tests) |
27 | * @param IBufferingStatsdDataFactory $statsdDataFactory |
28 | */ |
29 | public function __construct( |
30 | $classNameOrClassInstance, |
31 | IBufferingStatsdDataFactory $statsdDataFactory |
32 | ) { |
33 | // @codeCoverageIgnoreStart |
34 | if ( is_object( $classNameOrClassInstance ) ) { |
35 | if ( !defined( 'MW_PHPUNIT_TEST' ) ) { |
36 | throw new InvalidArgumentException( |
37 | 'JsonSchema should never be instantiated in production code' |
38 | ); |
39 | } |
40 | if ( !( $classNameOrClassInstance instanceof JsonSchema ) ) { |
41 | throw new InvalidArgumentException( |
42 | get_class( $classNameOrClassInstance ) . ' must be instance of ' . JsonSchema::class |
43 | ); |
44 | } |
45 | } |
46 | // @codeCoverageIgnoreEnd |
47 | |
48 | $this->jsonSchema = new JsonSchemaReader( $classNameOrClassInstance ); |
49 | $this->jsonSchemaBuilder = new JsonSchemaBuilder( $statsdDataFactory, $this->jsonSchema ); |
50 | $this->jsonSchemaIterator = new JsonSchemaIterator( $this->jsonSchema ); |
51 | $this->statsdDataFactory = $statsdDataFactory; |
52 | } |
53 | |
54 | /** |
55 | * @inheritDoc |
56 | */ |
57 | public function areSchemasSupported(): bool { |
58 | return true; |
59 | } |
60 | |
61 | /** |
62 | * @inheritDoc |
63 | */ |
64 | public function getSchemaBuilder(): SchemaBuilder { |
65 | return $this->jsonSchemaBuilder; |
66 | } |
67 | |
68 | /** |
69 | * @inheritDoc |
70 | */ |
71 | public function validateStrictly( $config ): ValidationStatus { |
72 | return $this->validate( $config, false ); |
73 | } |
74 | |
75 | /** |
76 | * @inheritDoc |
77 | */ |
78 | public function validatePermissively( $config ): ValidationStatus { |
79 | return $this->validate( $config, true ); |
80 | } |
81 | |
82 | /** |
83 | * @param mixed $config |
84 | * @param bool $modeForReading |
85 | * @return ValidationStatus |
86 | */ |
87 | private function validate( $config, bool $modeForReading ): ValidationStatus { |
88 | $start = microtime( true ); |
89 | |
90 | $validator = new Validator(); |
91 | $validator->validate( |
92 | $config, |
93 | $this->jsonSchemaBuilder->getRootSchema() |
94 | ); |
95 | if ( $validator->isValid() ) { |
96 | return ValidationStatus::newGood(); |
97 | } |
98 | $status = new ValidationStatus(); |
99 | foreach ( $validator->getErrors() as $error ) { |
100 | if ( $modeForReading && in_array( $error['constraint'], [ 'required', 'additionalProp', 'enum' ] ) ) { |
101 | $status->addWarning( |
102 | $error['property'], |
103 | $error['pointer'], |
104 | $error['message'], |
105 | [ 'constraint' => $error['constraint'] ], |
106 | ); |
107 | } else { |
108 | $status->addFatal( |
109 | $error['property'], |
110 | $error['pointer'], |
111 | $error['message'], |
112 | [ 'constraint' => $error['constraint'] ], |
113 | ); |
114 | } |
115 | } |
116 | |
117 | $this->statsdDataFactory->timing( |
118 | 'timing.communityConfiguration.JsonSchemaValidator.validate', |
119 | microtime( true ) - $start |
120 | ); |
121 | return $status; |
122 | } |
123 | |
124 | /** |
125 | * @inheritDoc |
126 | */ |
127 | public function getSchemaVersion(): ?string { |
128 | return $this->jsonSchema->getVersion(); |
129 | } |
130 | |
131 | public function getSchemaIterator(): Iterator { |
132 | return $this->jsonSchemaIterator; |
133 | } |
134 | } |