Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
FeaturedTemplatesSchemaValidator
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 9
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 factory
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 validate
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
56
 validateStrictly
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 validatePermissively
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 areSchemasSupported
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaBuilder
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaIterator
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaVersion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\TemplateData\Config;
5
6use Iterator;
7use MediaWiki\Config\Config;
8use MediaWiki\Extension\CommunityConfiguration\Schema\SchemaBuilder;
9use MediaWiki\Extension\CommunityConfiguration\Validation\IValidator;
10use MediaWiki\Extension\CommunityConfiguration\Validation\ValidationStatus;
11use MediaWiki\Extension\CommunityConfiguration\Validation\ValidatorFactory;
12use MediaWiki\Title\Title;
13
14/**
15 * @license GPL-2.0-or-later
16 */
17class FeaturedTemplatesSchemaValidator implements IValidator {
18
19    public function __construct(
20        private readonly IValidator $jsonSchemaValidator,
21        private readonly Config $config,
22    ) {
23    }
24
25    public static function factory( ValidatorFactory $validatorFactory, Config $mainConfig, string $jsonSchema ): self {
26        $jsonSchemaValidator = $validatorFactory->newValidator(
27            'TemplateData-FeaturedTemplates',
28            'jsonschema',
29            [ $jsonSchema ],
30        );
31        return new self( $jsonSchemaValidator, $mainConfig );
32    }
33
34    /**
35     * @param mixed $config
36     * @param string|null $version
37     * @return ValidationStatus
38     */
39    private function validate( $config, ?string $version = null ): ValidationStatus {
40        $resp = new ValidationStatus();
41        $configArray = json_decode( json_encode( $config ), true );
42
43        // Fatal: More than one property in FeaturedTemplates
44        if ( count( $configArray['FeaturedTemplates'] ) > 1 ) {
45            $resp->addFatal(
46                'FeaturedTemplates',
47                '',
48                'More than one property in FeaturedTemplates',
49            );
50        }
51        $featuredTemplates = $configArray['FeaturedTemplates'][0] ?? [];
52
53        // Fatal: Duplicates in the `titles` array
54        $titles = $featuredTemplates['titles'] ?? [];
55        $duplicates = array_diff_assoc( $titles, array_unique( $titles ) );
56        if ( count( $duplicates ) > 0 ) {
57            $resp->addFatal(
58                'FeaturedTemplates',
59                'titles',
60                'Duplicate titles in FeaturedTemplates',
61            );
62        }
63
64        // Fatal: Titles not in the TemplateData namespace
65        foreach ( $titles as $title ) {
66            $titleObject = Title::newFromText( $title );
67            // Check if the title is valid
68            if ( !$titleObject || !$titleObject->isKnown() ) {
69                $resp->addFatal(
70                    'FeaturedTemplates',
71                    'titles',
72                    'Invalid title in FeaturedTemplates',
73                );
74                continue;
75            }
76            $templateDataNamespaces = $this->config->get( 'TemplateDataEditorNamespaces' );
77            if ( !$titleObject->inNamespaces( $templateDataNamespaces ) ) {
78                $resp->addFatal(
79                    'FeaturedTemplates',
80                    'titles',
81                    'Title not in TemplateData namespace',
82                );
83            }
84        }
85        // Validate the config against the JSON schema
86        // This will add any validation errors to the response
87        $resp->merge( $this->jsonSchemaValidator->validateStrictly( $config, $version ) );
88
89        return $resp;
90    }
91
92    /** @inheritDoc */
93    public function validateStrictly( $config, ?string $version = null ): ValidationStatus {
94        $status = $this->jsonSchemaValidator->validateStrictly( $config, $version );
95        if ( !$status->isOK() ) {
96            return $status;
97        }
98        return $this->validate( $config, $version );
99    }
100
101    /** @inheritDoc */
102    public function validatePermissively( $config, ?string $version = null ): ValidationStatus {
103        return $this->jsonSchemaValidator->validatePermissively( $config, $version );
104    }
105
106    /** @inheritDoc */
107    public function areSchemasSupported(): bool {
108        return $this->jsonSchemaValidator->areSchemasSupported();
109    }
110
111    /** @inheritDoc */
112    public function getSchemaBuilder(): SchemaBuilder {
113        return $this->jsonSchemaValidator->getSchemaBuilder();
114    }
115
116    /** @inheritDoc */
117    public function getSchemaIterator(): Iterator {
118        return $this->jsonSchemaValidator->getSchemaIterator();
119    }
120
121    /** @inheritDoc */
122    public function getSchemaVersion(): ?string {
123        return $this->jsonSchemaValidator->getSchemaVersion();
124    }
125
126}