Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.10% covered (success)
93.10%
81 / 87
75.00% covered (warning)
75.00%
6 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZError
93.10% covered (success)
93.10%
81 / 87
75.00% covered (warning)
75.00%
6 / 8
26.22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDefinition
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
 isValid
78.57% covered (warning)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
7.48
 getZValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getZErrorType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMessage
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getHtmlMessage
93.02% covered (success)
93.02%
40 / 43
0.00% covered (danger)
0.00%
0 / 1
13.06
 getErrorData
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * WikiLambda ZError
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\ZObjects;
12
13use MediaWiki\Extension\WikiLambda\Registry\ZErrorTypeRegistry;
14use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
15use MediaWiki\Extension\WikiLambda\ZObjectUtils;
16use MediaWiki\Html\Html;
17
18class ZError extends ZObject {
19
20    /**
21     * Construct a new ZError instance.
22     *
23     * @param ZReference $type ZErrorType Zid
24     * @param ZObject $value Value that describes the ZError
25     */
26    public function __construct( $type, $value ) {
27        $this->data[ ZTypeRegistry::Z_ERROR_TYPE ] = $type;
28        $this->data[ ZTypeRegistry::Z_ERROR_VALUE ] = $value;
29    }
30
31    /**
32     * @inheritDoc
33     */
34    public static function getDefinition(): array {
35        return [
36            'type' => [
37                'type' => ZTypeRegistry::Z_REFERENCE,
38                'value' => ZTypeRegistry::Z_ERROR,
39            ],
40            'keys' => [
41                ZTypeRegistry::Z_ERROR_TYPE => [
42                    'type' => ZTypeRegistry::Z_ERRORTYPE,
43                    'required' => true,
44                ],
45                ZTypeRegistry::Z_ERROR_VALUE => [
46                    'type' => ZTypeRegistry::Z_OBJECT_TYPE,
47                    'required' => true,
48                ],
49            ],
50        ];
51    }
52
53    /**
54     * @inheritDoc
55     */
56    public function isValid(): bool {
57        // Type must be a valid Zid that references a ZObject of type Z50
58        if ( !isset( $this->data[ ZTypeRegistry::Z_ERROR_TYPE ] ) ) {
59            return false;
60        }
61        if ( !( $this->data[ ZTypeRegistry::Z_ERROR_TYPE  ] instanceof ZReference ) ) {
62            return false;
63        }
64        $errorType = $this->data[ ZTypeRegistry::Z_ERROR_TYPE ]->getZValue();
65        if ( !ZObjectUtils::isValidZObjectReference( $errorType ) ) {
66            return false;
67        }
68        if ( !ZErrorTypeRegistry::singleton()->instanceOfZErrorType( $errorType ) ) {
69            return false;
70        }
71        // Value must be a valid ZObject
72        if ( !isset( $this->data[ ZTypeRegistry::Z_ERROR_VALUE ] ) ) {
73            return false;
74        }
75        if ( !( $this->data[ ZTypeRegistry::Z_ERROR_VALUE ] instanceof ZObject ) ) {
76            return false;
77        }
78        return $this->getZValue()->isValid();
79    }
80
81    /**
82     * Get the content of the ZError value.
83     *
84     * @return ZObject Value that describes this ZError
85     */
86    public function getZValue(): ZObject {
87        return $this->data[ ZTypeRegistry::Z_ERROR_VALUE ];
88    }
89
90    /**
91     * Get the Zid that identifies the ZErrorType that describes this ZError
92     *
93     * @return string ZErrorType Zid
94     */
95    public function getZErrorType(): string {
96        return $this->data[ ZTypeRegistry::Z_ERROR_TYPE ]->getZValue();
97    }
98
99    /**
100     * Get a human-readable one-line string that identifies the ZError information
101     *
102     * @param string $renderLanguageCode Language code in which to render the message; if not
103     *   provided, English is used by default.
104     * @return string ZError message
105     */
106    public function getMessage( string $renderLanguageCode = 'en' ): string {
107        return ZErrorTypeRegistry::singleton()->getZErrorTypeLabel(
108            $this->getZErrorType(),
109            $renderLanguageCode
110        );
111    }
112
113    /**
114     * Get a human-readable one-line string that identifies the ZError information
115     *
116     * @param string $renderLanguageCode Language code in which to render the message; if not
117     *   provided, English is used by default.
118     * @return string ZError message
119     */
120    public function getHtmlMessage( string $renderLanguageCode = 'en' ): string {
121        $message = ZErrorTypeRegistry::singleton()->getZErrorTypeLabel(
122            $this->getZErrorType(),
123            $renderLanguageCode
124        );
125        $messages = [];
126
127        $errorType = $this->getZErrorType();
128
129        // Errors that have message key: Z500, Z557
130        // Get error message from K1 (if not null)
131        if (
132            ( $errorType === ZErrorTypeRegistry::Z_ERROR_UNKNOWN ) ||
133            ( $errorType === ZErrorTypeRegistry::Z_ERROR_USER_CANNOT_EDIT )
134        ) {
135            $errorValue = $this->getZValue();
136            $messageKey = $errorValue->getValueByKey( 'K1' );
137            $message = $messageKey ? $messageKey->getZValue() : $message;
138        }
139
140        // Errors that can have children: Z509, Z502, Z522, Z526
141        // List of children in K1:
142        // * Z509/List of errors
143        if ( $errorType === ZErrorTypeRegistry::Z_ERROR_LIST ) {
144            $errorValue = $this->getZValue();
145            $subErrors = $errorValue->getValueByKey( 'K1' );
146
147            if ( is_array( $subErrors ) || ( $subErrors instanceof ZTypedList ) ) {
148                foreach ( ZObjectUtils::getIterativeList( $subErrors ) as $subError ) {
149                    $messages[] = Html::rawElement(
150                        'li',
151                        [ 'class' => 'ext-wikilambda-app-suberror-list__item' ],
152                        $subError->getHtmlMessage( $renderLanguageCode )
153                    );
154                }
155            }
156        }
157
158        // Only child in K2:
159        // * Z502/Not wellformed
160        // * Z522/Array element not wellformed
161        if (
162            ( $errorType === ZErrorTypeRegistry::Z_ERROR_NOT_WELLFORMED ) ||
163            ( $errorType === ZErrorTypeRegistry::Z_ERROR_KEY_VALUE_NOT_WELLFORMED ) ||
164            ( $errorType === ZErrorTypeRegistry::Z_ERROR_ARRAY_ELEMENT_NOT_WELLFORMED )
165        ) {
166            $errorValue = $this->getZValue();
167            $subError = $errorValue->getValueByKey( 'K2' );
168            '@phan-var ZError $subError';
169            $messages[] = Html::rawElement(
170                'li',
171                [ 'class' => 'ext-wikilambda-app-suberror-list__item' ],
172                $subError->getHtmlMessage( $renderLanguageCode )
173            );
174        }
175
176        // Add failing key information to message:
177        // * Z526/Key value not wellformed
178        if ( $errorType === ZErrorTypeRegistry::Z_ERROR_KEY_VALUE_NOT_WELLFORMED ) {
179            $errorValue = $this->getZValue();
180            $errorKey = $errorValue->getValueByKey( 'K1' );
181            '@phan-var \MediaWiki\Extension\WikiLambda\ZObjects\ZKey $errorKey';
182            $errorKeyLabel = $errorKey->getKeyLabel();
183            $message .= ': ' . $errorKeyLabel;
184        }
185
186        if ( count( $messages ) > 0 ) {
187            $message .= Html::rawElement(
188                'ul',
189                [ 'class' => 'ext-wikilambda-app-suberror-list' ],
190                implode( '', $messages )
191            );
192        }
193
194        return $message;
195    }
196
197    /**
198     * Get all ZError related information in different forms for API failure response.
199     *
200     * @return array
201     */
202    public function getErrorData() {
203        return [
204            'title' => $this->getMessage(),
205            'message' => $this->getHtmlMessage(),
206            'zerror' => $this->getSerialized(),
207            'labelled' => $this->getHumanReadable(),
208        ];
209    }
210}