Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.65% covered (warning)
80.65%
25 / 31
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZErrorTypeRegistry
80.65% covered (warning)
80.65%
25 / 31
71.43% covered (warning)
71.43%
5 / 7
16.63
0.00% covered (danger)
0.00%
0 / 1
 initialize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isZErrorTypeKnown
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 fetchZErrorType
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 instanceOfZErrorType
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 isZErrorTypeCached
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isBuiltinZErrorType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getZErrorTypeLabel
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
3.47
1<?php
2/**
3 * WikiLambda ZErrorTypeRegistry
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\Registry;
12
13use MediaWiki\Extension\WikiLambda\WikiLambdaServices;
14use MediaWiki\Extension\WikiLambda\ZErrorException;
15use MediaWiki\Extension\WikiLambda\ZObjectContent;
16use MediaWiki\Title\Title;
17
18/**
19 * A registry service for ZErrorType
20 */
21class ZErrorTypeRegistry extends ZObjectRegistry {
22
23    // TODO (T300512): Bring all constants (error types ZIDs) to schemata
24    public const Z_ERROR_UNKNOWN = 'Z500';
25    public const Z_ERROR_INVALID_SYNTAX = 'Z501';
26    public const Z_ERROR_NOT_WELLFORMED = 'Z502';
27    public const Z_ERROR_ZID_NOT_FOUND = 'Z504';
28    public const Z_ERROR_ARGUMENT_TYPE_MISMATCH = 'Z506';
29    public const Z_ERROR_EVALUATION = 'Z507';
30    public const Z_ERROR_LIST = 'Z509';
31    public const Z_ERROR_MISSING_KEY = 'Z511';
32    public const Z_ERROR_MISSING_PERSISTENT_VALUE = 'Z513';
33    public const Z_ERROR_UNDEFINED_LIST_TYPE = 'Z519';
34    public const Z_ERROR_WRONG_LIST_TYPE = 'Z520';
35    public const Z_ERROR_NOT_NUMBER_BOOLEAN_NULL = 'Z521';
36    public const Z_ERROR_ARRAY_ELEMENT_NOT_WELLFORMED = 'Z522';
37    public const Z_ERROR_MISSING_TYPE = 'Z523';
38    public const Z_ERROR_TYPE_NOT_STRING_ARRAY = 'Z524';
39    public const Z_ERROR_INVALID_KEY = 'Z525';
40    public const Z_ERROR_KEY_VALUE_NOT_WELLFORMED = 'Z526';
41    public const Z_ERROR_STRING_VALUE_MISSING = 'Z532';
42    public const Z_ERROR_STRING_VALUE_WRONG_TYPE = 'Z533';
43    public const Z_ERROR_REFERENCE_VALUE_MISSING = 'Z535';
44    public const Z_ERROR_REFERENCE_VALUE_WRONG_TYPE = 'Z536';
45    public const Z_ERROR_REFERENCE_VALUE_INVALID = 'Z537';
46    public const Z_ERROR_WRONG_NAMESPACE = 'Z538';
47    public const Z_ERROR_WRONG_CONTENT_TYPE = 'Z539';
48    public const Z_ERROR_INVALID_LANG_CODE = 'Z540';
49    public const Z_ERROR_LANG_NOT_FOUND = 'Z541';
50    public const Z_ERROR_UNEXPECTED_ZTYPE = 'Z542';
51    public const Z_ERROR_ZTYPE_NOT_FOUND = 'Z543';
52    public const Z_ERROR_CONFLICTING_TYPE_NAMES = 'Z544';
53    public const Z_ERROR_CONFLICTING_TYPE_ZIDS = 'Z545';
54    public const Z_ERROR_BUILTIN_TYPE_NOT_FOUND = 'Z546';
55    public const Z_ERROR_INVALID_FORMAT = 'Z547';
56    public const Z_ERROR_INVALID_JSON = 'Z548';
57    public const Z_ERROR_INVALID_REFERENCE = 'Z549';
58    public const Z_ERROR_UNKNOWN_REFERENCE = 'Z550';
59    public const Z_ERROR_SCHEMA_TYPE_MISMATCH = 'Z551';
60    public const Z_ERROR_ARRAY_TYPE_MISMATCH = 'Z552';
61    public const Z_ERROR_DISALLOWED_ROOT_ZOBJECT = 'Z553';
62    public const Z_ERROR_LABEL_CLASH = 'Z554';
63    public const Z_ERROR_UNMATCHING_ZID = 'Z555';
64    public const Z_ERROR_INVALID_TITLE = 'Z556';
65    public const Z_ERROR_USER_CANNOT_EDIT = 'Z557';
66    public const Z_ERROR_USER_CANNOT_RUN = 'Z559';
67    public const Z_ERROR_ORCHESTRATOR_RATE_LIMIT = 'Z570';
68    public const Z_ERROR_EVALUATOR_RATE_LIMIT = 'Z571';
69
70    private const BUILT_IN_ERRORS = [
71        'Z500' => 'Z_ERROR_UNKNOWN',
72        'Z501' => 'Z_ERROR_INVALID_SYNTAX',
73        'Z502' => 'Z_ERROR_NOT_WELLFORMED',
74        'Z504' => 'Z_ERROR_ZID_NOT_FOUND',
75        'Z506' => 'Z_ERROR_ARGUMENT_TYPE_MISMATCH',
76        'Z507' => 'Z_ERROR_EVALUATION',
77        'Z509' => 'Z_ERROR_LIST',
78        'Z511' => 'Z_ERROR_MISSING_KEY',
79        'Z513' => 'Z_ERROR_MISSING_PERSISTENT_VALUE',
80        'Z519' => 'Z_ERROR_UNDEFINED_LIST_TYPE',
81        'Z521' => 'Z_ERROR_NOT_NUMBER_BOOLEAN_NULL',
82        'Z522' => 'Z_ERROR_ARRAY_ELEMENT_NOT_WELLFORMED',
83        'Z523' => 'Z_ERROR_MISSING_TYPE',
84        'Z524' => 'Z_ERROR_TYPE_NOT_STRING_ARRAY',
85        'Z525' => 'Z_ERROR_INVALID_KEY',
86        'Z526' => 'Z_ERROR_KEY_VALUE_NOT_WELLFORMED',
87        'Z532' => 'Z_ERROR_STRING_VALUE_MISSING',
88        'Z533' => 'Z_ERROR_STRING_VALUE_WRONG_TYPE',
89        'Z535' => 'Z_ERROR_REFERENCE_VALUE_MISSING',
90        'Z536' => 'Z_ERROR_REFERENCE_VALUE_WRONG_TYPE',
91        'Z537' => 'Z_ERROR_REFERENCE_VALUE_INVALID',
92        'Z538' => 'Z_ERROR_WRONG_NAMESPACE',
93        'Z539' => 'Z_ERROR_WRONG_CONTENT_TYPE',
94        'Z540' => 'Z_ERROR_INVALID_LANG_CODE',
95        'Z541' => 'Z_ERROR_LANG_NOT_FOUND',
96        'Z542' => 'Z_ERROR_UNEXPECTED_ZTYPE',
97        'Z543' => 'Z_ERROR_ZTYPE_NOT_FOUND',
98        'Z544' => 'Z_ERROR_CONFLICTING_TYPE_NAMES',
99        'Z545' => 'Z_ERROR_CONFLICTING_TYPE_ZIDS',
100        'Z546' => 'Z_ERROR_BUILTIN_TYPE_NOT_FOUND',
101        'Z547' => 'Z_ERROR_INVALID_FORMAT',
102        'Z548' => 'Z_ERROR_INVALID_JSON',
103        'Z549' => 'Z_ERROR_INVALID_REFERENCE',
104        'Z550' => 'Z_ERROR_UNKNOWN_REFERENCE',
105        'Z551' => 'Z_ERROR_SCHEMA_TYPE_MISMATCH',
106        'Z552' => 'Z_ERROR_ARRAY_TYPE_MISMATCH',
107        'Z553' => 'Z_ERROR_DISALLOWED_ROOT_ZOBJECT',
108        'Z554' => 'Z_ERROR_LABEL_CLASH',
109        'Z555' => 'Z_ERROR_UNMATCHING_ZID',
110        'Z556' => 'Z_ERROR_INVALID_TITLE',
111        'Z557' => 'Z_ERROR_USER_CANNOT_EDIT',
112        'Z559' => 'Z_ERROR_USER_CANNOT_RUN',
113        'Z570' => 'Z_ERROR_ORCHESTRATOR_RATE_LIMIT',
114        'Z571' => 'Z_ERROR_EVALUATOR_RATE_LIMIT',
115    ];
116
117    /**
118     * Initialize ZErrorTypeRegistry
119     */
120    protected function initialize(): void {
121        // Registry for ZObjects of type ZErrorType/Z500
122        $this->type = ZTypeRegistry::Z_ERRORTYPE;
123    }
124
125    /**
126     * Check if the given ZErrorType Zid is known
127     *
128     * @param string $errorType
129     * @return bool
130     */
131    public function isZErrorTypeKnown( string $errorType ): bool {
132        if ( $this->isZErrorTypeCached( $errorType ) ) {
133            return true;
134        }
135
136        if ( $this->isBuiltinZErrorType( $errorType ) ) {
137            return true;
138        }
139
140        $zObject = $this->fetchZErrorType( $errorType );
141        if ( $zObject === false ) {
142            return false;
143        }
144
145        $this->register( $errorType, $zObject->getLabels()->getStringForLanguageCode( 'en' ) );
146        return true;
147    }
148
149    /**
150     * Fetches a given error type Zid from the database, throwing error if the ZErrorType does not
151     * exist or if the fetched object is not of the wanted type
152     *
153     * @param string $errorType
154     * @return ZObjectContent|bool Found ZObject
155     * @throws ZErrorException
156     */
157    private function fetchZErrorType( string $errorType ) {
158        // TODO (T338253): This is quite expensive. Store this in a metadata DB table, instead of fetching it live?
159        $title = Title::newFromText( $errorType, NS_MAIN );
160        $zObjectStore = WikiLambdaServices::getZObjectStore();
161        $zObject = $zObjectStore->fetchZObjectByTitle( $title );
162
163        if ( $zObject === false ) {
164            return false;
165            // throw new ZErrorException(
166            //     ZErrorFactory::createZErrorInstance(
167            //         self::Z_ERROR_ZID_NOT_FOUND,
168            //         [ "data" => $errorType ]
169            //     )
170            // );
171        }
172
173        if ( $zObject->getZType() !== ZTypeRegistry::Z_ERRORTYPE ) {
174            return false;
175            // throw new ZErrorException(
176            //     ZErrorFactory::createZErrorInstance(
177            //         self::Z_ERROR_UNEXPECTED_ZTYPE,
178            //         [
179            //             "expected" => ZTypeRegistry::Z_ERRORTYPE,
180            //             "used" => $errorType
181            //         ]
182            //     )
183            // );
184        }
185
186        return $zObject;
187    }
188
189    /**
190     * Check if the given Zid belongs to a ZErrorType
191     *
192     * @param string $zid
193     * @return bool
194     */
195    public function instanceOfZErrorType( string $zid ): bool {
196        try {
197            return $this->isZErrorTypeKnown( $zid );
198        } catch ( ZErrorException $e ) {
199            return false;
200        }
201    }
202
203    /**
204     * Check if the given Zid is an already cached ZErrorType (Z50)
205     *
206     * @param string $errorType
207     * @return bool
208     */
209    public function isZErrorTypeCached( string $errorType ): bool {
210        return array_key_exists( $errorType, $this->registry );
211    }
212
213    /**
214     * Check if the given Zid belongs to a builtin ZErrorType
215     *
216     * @param string $errorType
217     * @return bool
218     */
219    private function isBuiltinZErrorType( string $errorType ): bool {
220        return array_key_exists( $errorType, self::BUILT_IN_ERRORS );
221    }
222
223    /**
224     * Gets the ZErrorType label in English
225     *
226     * @param string $errorType
227     * @return string
228     * @throws ZErrorException
229     */
230    public function getZErrorTypeLabel( string $errorType ): string {
231        if ( $this->isZErrorTypeCached( $errorType ) ) {
232            return $this->registry[ $errorType ];
233        }
234
235        $zObject = $this->fetchZErrorType( $errorType );
236        if ( $zObject === false ) {
237            return "Unknown error $errorType";
238        }
239
240        // TODO (T362236): Take the rendering language as a parameter, don't default to English
241        $errorLabel = $zObject->getLabels()->getStringForLanguageCode( 'en' );
242        $this->register( $errorType, $errorLabel );
243
244        return $errorLabel;
245    }
246}