Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.59% covered (success)
92.59%
75 / 81
75.00% covered (warning)
75.00%
6 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZError
92.59% covered (success)
92.59%
75 / 81
75.00% covered (warning)
75.00%
6 / 8
26.27
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%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHtmlMessage
92.50% covered (success)
92.50%
37 / 40
0.00% covered (danger)
0.00%
0 / 1
13.07
 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     * @return string ZError message
103     */
104    public function getMessage(): string {
105        // TODO (T362236): Add the rendering language as a parameter, don't default to English
106        return ZErrorTypeRegistry::singleton()->getZErrorTypeLabel( $this->getZErrorType() );
107    }
108
109    /**
110     * Get a human-readable one-line string that identifies the ZError information
111     *
112     * @return string ZError message
113     */
114    public function getHtmlMessage(): string {
115        // TODO (T362236): Add the rendering language as a parameter, don't default to English
116        $message = ZErrorTypeRegistry::singleton()->getZErrorTypeLabel( $this->getZErrorType() );
117        $messages = [];
118
119        $errorType = $this->getZErrorType();
120
121        // Errors that have message key: Z500, Z557
122        // Get error message from K1 (if not null)
123        if (
124            ( $errorType === ZErrorTypeRegistry::Z_ERROR_UNKNOWN ) ||
125            ( $errorType === ZErrorTypeRegistry::Z_ERROR_USER_CANNOT_EDIT )
126        ) {
127            $errorValue = $this->getZValue();
128            $messageKey = $errorValue->getValueByKey( 'K1' );
129            $message = $messageKey ? $messageKey->getZValue() : $message;
130        }
131
132        // Errors that can have children: Z509, Z502, Z522, Z526
133        // List of children in K1:
134        // * Z509/List of errors
135        if ( $errorType === ZErrorTypeRegistry::Z_ERROR_LIST ) {
136            $errorValue = $this->getZValue();
137            $subErrors = $errorValue->getValueByKey( 'K1' );
138
139            if ( is_array( $subErrors ) || ( $subErrors instanceof ZTypedList ) ) {
140                foreach ( ZObjectUtils::getIterativeList( $subErrors ) as $subError ) {
141                    $messages[] = Html::rawElement(
142                        'li',
143                        [ 'class' => 'ext-wikilambda-app-suberror-list__item' ],
144                        $subError->getHtmlMessage()
145                    );
146                }
147            }
148        }
149
150        // Only child in K2:
151        // * Z502/Not wellformed
152        // * Z522/Array element not wellformed
153        if (
154            ( $errorType === ZErrorTypeRegistry::Z_ERROR_NOT_WELLFORMED ) ||
155            ( $errorType === ZErrorTypeRegistry::Z_ERROR_KEY_VALUE_NOT_WELLFORMED ) ||
156            ( $errorType === ZErrorTypeRegistry::Z_ERROR_ARRAY_ELEMENT_NOT_WELLFORMED )
157        ) {
158            $errorValue = $this->getZValue();
159            $subError = $errorValue->getValueByKey( 'K2' );
160            '@phan-var ZError $subError';
161            $messages[] = Html::rawElement(
162                'li',
163                [ 'class' => 'ext-wikilambda-app-suberror-list__item' ],
164                $subError->getHtmlMessage()
165            );
166        }
167
168        // Add failing key information to message:
169        // * Z526/Key value not wellformed
170        if ( $errorType === ZErrorTypeRegistry::Z_ERROR_KEY_VALUE_NOT_WELLFORMED ) {
171            $errorValue = $this->getZValue();
172            $errorKey = $errorValue->getValueByKey( 'K1' );
173            '@phan-var \MediaWiki\Extension\WikiLambda\ZObjects\ZKey $errorKey';
174            $errorKeyLabel = $errorKey->getKeyLabel();
175            $message .= ': ' . $errorKeyLabel;
176        }
177
178        if ( count( $messages ) > 0 ) {
179            $message .= Html::rawElement(
180                'ul',
181                [ 'class' => 'ext-wikilambda-app-suberror-list' ],
182                implode( '', $messages )
183            );
184        }
185
186        return $message;
187    }
188
189    /**
190     * Get all ZError related information in different forms for API failure response.
191     *
192     * @return array
193     */
194    public function getErrorData() {
195        return [
196            'title' => $this->getMessage(),
197            'message' => $this->getHtmlMessage(),
198            'zerror' => $this->getSerialized(),
199            'labelled' => $this->getHumanReadable(),
200        ];
201    }
202}