Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.16% covered (success)
92.16%
94 / 102
84.62% covered (warning)
84.62%
11 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZType
92.16% covered (success)
92.16%
94 / 102
84.62% covered (warning)
84.62%
11 / 13
34.56
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 getDefinition
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
1
 isValid
74.07% covered (warning)
74.07%
20 / 27
0.00% covered (danger)
0.00%
0 / 1
17.42
 getTypeId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypeKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypeValidator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEqualityFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getRendererFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getParserFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getDeserialisers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSerialisers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEnumType
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 getZKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * WikiLambda ZType
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\ZTypeRegistry;
14
15class ZType extends ZObject {
16
17    /**
18     * Construct a ZType instance given the identity ZReference, a ZTypedList of ZKeys,
19     * and a ZReference to the type validator
20     *
21     * @param ZObject $identity
22     * @param ZObject $keys
23     * @param ZObject $validator
24     * @param ?ZObject $equality
25     * @param ?ZObject $renderer
26     * @param ?ZObject $parser
27     * @param ?ZTypedList $deserialisers
28     * @param ?ZTypedList $serialisers
29     */
30    public function __construct(
31        $identity, $keys, $validator,
32        ?ZObject $equality = null,
33        ?ZObject $renderer = null, ?ZObject $parser = null,
34        ?ZTypedList $deserialisers = null, ?ZTypedList $serialisers = null
35    ) {
36        $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] = $identity;
37        $this->data[ ZTypeRegistry::Z_TYPE_KEYS ] = $keys;
38        $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] = $validator;
39        $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ] = $equality ?? false;
40        $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ] = $renderer ?? false;
41        $this->data[ ZTypeRegistry::Z_TYPE_PARSER ] = $parser ?? false;
42        $this->data[ ZTypeRegistry::Z_TYPE_DESERIALISERS ] = $deserialisers ??
43            new ZTypedList( ZTypedList::buildType( new ZReference( ZTypeRegistry::Z_DESERIALISER ) ) );
44        $this->data[ ZTypeRegistry::Z_TYPE_SERIALISERS ] = $serialisers ??
45            new ZTypedList( ZTypedList::buildType( new ZReference( ZTypeRegistry::Z_SERIALISER ) ) );
46    }
47
48    /**
49     * @inheritDoc
50     */
51    public static function getDefinition(): array {
52        return [
53            'type' => [
54                'type' => ZTypeRegistry::Z_REFERENCE,
55                'value' => ZTypeRegistry::Z_TYPE,
56            ],
57            'keys' => [
58                ZTypeRegistry::Z_TYPE_IDENTITY => [
59                    // NOTE: Allows Z0.
60                    'type' => ZTypeRegistry::BUILTIN_REFERENCE_NULLABLE,
61                ],
62                ZTypeRegistry::Z_TYPE_KEYS => [
63                    // TODO (T362257): Walk the array of ZKeys.
64                    'type' => ZTypeRegistry::HACK_ARRAY_Z_KEY,
65                    'required' => true,
66                ],
67                ZTypeRegistry::Z_TYPE_VALIDATOR => [
68                    // NOTE: Allows Z0 until we support ZFunctions.
69                    'type' => ZTypeRegistry::BUILTIN_REFERENCE_NULLABLE,
70                ],
71                ZTypeRegistry::Z_TYPE_EQUALITY => [
72                    'type' => ZTypeRegistry::Z_FUNCTION,
73                    'required' => false,
74                ],
75                ZTypeRegistry::Z_TYPE_RENDERER => [
76                    'type' => ZTypeRegistry::Z_FUNCTION,
77                    'required' => false,
78                ],
79                ZTypeRegistry::Z_TYPE_PARSER => [
80                    'type' => ZTypeRegistry::Z_FUNCTION,
81                    'required' => false,
82                ],
83                ZTypeRegistry::Z_TYPE_DESERIALISERS => [
84                    'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST,
85                    'required' => false,
86                ],
87                ZTypeRegistry::Z_TYPE_SERIALISERS => [
88                    'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST,
89                    'required' => false,
90                ],
91            ],
92        ];
93    }
94
95    /**
96     * @inheritDoc
97     */
98    public function isValid(): bool {
99        // Identity must be set to a valid ZReference (or special case of 'Z0')
100        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] ) ) {
101            return false;
102        }
103        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] instanceof ZReference ) ) {
104            return false;
105        }
106        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ]->isValid() ) ) {
107            return false;
108        }
109
110        // Key map must be set to an array or ZTypedList of zero or more ZKeys, all valid
111        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_KEYS ] ) ) {
112            return false;
113        }
114        $keys = $this->data[ ZTypeRegistry::Z_TYPE_KEYS ];
115        if ( !is_array( $keys ) ) {
116            if ( $keys instanceof ZTypedList ) {
117                if ( $keys->getElementType()->getZValue() !== ZTypeRegistry::Z_KEY ) {
118                    return false;
119                }
120                $keys = $keys->getAsArray();
121            } else {
122                return false;
123            }
124        }
125        foreach ( $keys as $key ) {
126            if ( !( $key instanceof ZKey ) ) {
127                return false;
128            }
129            if ( !$key->isValid() ) {
130                return false;
131            }
132        }
133
134        // Validator must be set to a valid ZKey reference
135        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] ) ) {
136            return false;
137        }
138        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] instanceof ZReference ) ) {
139            return false;
140        }
141        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ]->isValid() ) ) {
142            return false;
143        }
144        // TODO (T362242): Actually check that the validator is a ZFunction that applies to us.
145
146        // TODO (T362243): Check the equality, renderer, parser, and type converter keys.
147
148        return true;
149    }
150
151    /**
152     * Get the representation of th ZType Zid
153     *
154     * @return ZReference|ZFunctionCall
155     */
156    public function getTypeId() {
157        return $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ];
158    }
159
160    /**
161     * Get a list with the set of ZKeys for this ZType
162     *
163     * @return ZTypedList
164     */
165    public function getTypeKeys() {
166        return $this->data[ ZTypeRegistry::Z_TYPE_KEYS ];
167    }
168
169    /**
170     * Get the string representation of the ZReference to this ZType's validator function
171     *
172     * @return string
173     */
174    public function getTypeValidator() {
175        return $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ]->getZValue();
176    }
177
178    /**
179     * Get the string representation of the ZReference to this ZType's equality function,
180     * or false if there is none.
181     *
182     * @return string|false
183     */
184    public function getEqualityFunction() {
185        return $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ] ?
186            $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ]->getZValue() :
187            false;
188    }
189
190    /**
191     * Get the string representation of the ZReference to this ZType's rendering function,
192     * or false if there is none.
193     *
194     * @return string|false
195     */
196    public function getRendererFunction() {
197        return $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ] ?
198            $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ]->getZValue() :
199            false;
200    }
201
202    /**
203     * Get the string representation of the ZReference to this ZType's parsing function,
204     * or false if there is none.
205     *
206     * @return string|false
207     */
208    public function getParserFunction() {
209        return $this->data[ ZTypeRegistry::Z_TYPE_PARSER ] ?
210            $this->data[ ZTypeRegistry::Z_TYPE_PARSER ]->getZValue() :
211            false;
212    }
213
214    /**
215     * Get the ZList of this ZType's deserialisers
216     *
217     * @return ZTypedList
218     */
219    public function getDeserialisers() {
220        return $this->data[ ZTypeRegistry::Z_TYPE_DESERIALISERS ];
221    }
222
223    /**
224     * Get the ZList of this ZType's serialisers
225     *
226     * @return ZTypedList
227     */
228    public function getSerialisers() {
229        return $this->data[ ZTypeRegistry::Z_TYPE_SERIALISERS ];
230    }
231
232    /**
233     * Return whether the type has an identity key but is not
234     * one of the non-enum reserved types with identity key:
235     * * Type/Z4
236     * * Function/Z8
237     * * Deserialiser/Z46
238     * * Serialiser/Z64
239     *
240     * @return bool
241     */
242    public function isEnumType() {
243        $typeId = $this->getTypeId()->getZValue();
244
245        if ( in_array( $typeId, ZTypeRegistry::EXCLUDE_TYPES_FROM_ENUMS ) ) {
246            // Type has identity key but excluded from enum; return false
247            return false;
248        }
249
250        $keys = $this->getTypeKeys()->getAsArray();
251        foreach ( $keys as $key ) {
252            if ( $key->getIsIdentity() ) {
253                return true;
254            }
255        }
256        return false;
257    }
258
259    /**
260     * Get the ZKey of a given key reference from the set of ZKeys of this ZType or
261     * null if the ZKey is not available.
262     *
263     * @param string $key
264     * @return ZKey|null
265     */
266    public function getZKey( $key ) {
267        $keys = $this->getTypeKeys()->getAsArray();
268        foreach ( $keys as $zkey ) {
269            if ( $zkey->getKeyId() === $key ) {
270                return $zkey;
271            }
272        }
273        return null;
274    }
275}