Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.72% covered (warning)
83.72%
36 / 43
44.44% covered (danger)
44.44%
4 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
JsonSchemaBuilder
83.72% covered (warning)
83.72%
36 / 43
44.44% covered (danger)
44.44%
4 / 9
15.97
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getJsonSchemaReader
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
2.86
 getSchemaName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getVersionManager
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaReader
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRootSchema
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 getRootProperties
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultFromSchema
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
5.03
 getDefaultsMap
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Extension\CommunityConfiguration\Schema;
4
5use IBufferingStatsdDataFactory;
6use stdClass;
7
8class JsonSchemaBuilder implements SchemaBuilder {
9
10    private IBufferingStatsdDataFactory $statsdDataFactory;
11    private JsonSchemaReader $jsonSchema;
12    private JsonSchemaVersionManager $versionManager;
13
14    public function __construct(
15        IBufferingStatsdDataFactory $statsdDataFactory,
16        JsonSchemaReader $jsonSchema
17    ) {
18        $this->statsdDataFactory = $statsdDataFactory;
19        $this->jsonSchema = $jsonSchema;
20        $this->versionManager = new JsonSchemaVersionManager( $this->jsonSchema );
21    }
22
23    /**
24     * Get schema reader for given version
25     *
26     * @param string|null $version
27     * @return JsonSchemaReader
28     */
29    private function getJsonSchemaReader( ?string $version = null ): JsonSchemaReader {
30        if ( $version === null ) {
31            return $this->jsonSchema;
32        }
33
34        return $this->versionManager->getVersionForSchema(
35            $version
36        );
37    }
38
39    /**
40     * @inheritDoc
41     */
42    public function getSchemaName(): string {
43        return $this->getJsonSchemaReader()->getSchemaId();
44    }
45
46    /**
47     * @inheritDoc
48     */
49    public function getVersionManager(): SchemaVersionManager {
50        return $this->versionManager;
51    }
52
53    /**
54     * @inheritDoc
55     */
56    public function getSchemaReader(): SchemaReader {
57        return $this->jsonSchema;
58    }
59
60    /**
61     * @inheritDoc
62     */
63    public function getRootSchema( ?string $version = null ): array {
64        $start = microtime( true );
65        $reader = $this->getJsonSchemaReader( $version );
66        $reader->assertIsSchema();
67
68        $result = array_merge( [
69            '$schema' => $this->jsonSchema->getJsonSchemaVersion(),
70            '$id' => $this->jsonSchema->getSchemaId(),
71            JsonSchema::ADDITIONAL_PROPERTIES => false,
72        ], $reader->getReflectionSchemaSource()->loadAsSchema( true ) );
73        $this->statsdDataFactory->timing(
74            'timing.communityConfiguration.JsonSchemaBuilder.getRootSchema',
75            microtime( true ) - $start
76        );
77        return $result;
78    }
79
80    /**
81     * @inheritDoc
82     */
83    public function getRootProperties( ?string $version = null ): array {
84        return $this->getRootSchema( $version )[JsonSchema::PROPERTIES];
85    }
86
87    /**
88     * Get a default from a JSON schema specification
89     *
90     * Takes into account dynamic defaults.
91     *
92     * @param array $schema
93     * @return mixed
94     */
95    private function getDefaultFromSchema( array $schema ) {
96        if ( isset( $schema[JsonSchema::DYNAMIC_DEFAULT] ) ) {
97            $result = call_user_func( $schema[JsonSchema::DYNAMIC_DEFAULT]['callback'] );
98        } else {
99            $result = $schema['default'] ?? null;
100        }
101
102        if ( $schema[JsonSchema::TYPE] === JsonSchema::TYPE_OBJECT ) {
103            // Convert the value to an object when TYPE_OBJECT is expected
104            $result = (object)$result;
105        }
106
107        // process defaults for objects recursively
108        if ( is_object( $result ) ) {
109            foreach ( $schema['properties'] ?? [] as $name => $subSchema ) {
110                $result->{$name} = $this->getDefaultFromSchema( $subSchema );
111            }
112        }
113
114        return $result;
115    }
116
117    /**
118     * @inheritDoc
119     */
120    public function getDefaultsMap( ?string $version = null ): stdClass {
121        $start = microtime( true );
122        $res = new stdClass();
123        foreach ( $this->getRootProperties( $version ) as $key => $specification ) {
124            $res->{$key} = $this->getDefaultFromSchema( $specification );
125        }
126        $this->statsdDataFactory->timing(
127            'timing.communityConfiguration.JsonSchemaBuilder.getDefaultsMap',
128            microtime( true ) - $start
129        );
130        return $res;
131    }
132}