Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.61% covered (success)
96.61%
57 / 59
92.31% covered (success)
92.31%
12 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ViolationMessageSerializer
96.61% covered (success)
96.61%
57 / 59
92.31% covered (success)
92.31%
12 / 13
23
0.00% covered (danger)
0.00%
0 / 1
 abbreviateViolationMessageKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serialize
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 serializeArgument
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
2
 serializeStringByIdentity
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeStringListByIdentity
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 serializeEntityId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeEntityIdList
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeItemIdSnakValue
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 serializeItemIdSnakValueList
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeDataValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeContextType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
5
 serializeContextTypeList
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serializeMultilingualText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare( strict_types = 1 );
4
5namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Message;
6
7use DataValues\DataValue;
8use DataValues\MultilingualTextValue;
9use InvalidArgumentException;
10use LogicException;
11use Serializers\Serializer;
12use Wikibase\DataModel\Entity\EntityId;
13use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context;
14use WikibaseQuality\ConstraintReport\ConstraintCheck\ItemIdSnakValue;
15use Wikimedia\Assert\Assert;
16
17/**
18 * A serializer for {@link ViolationMessage}s.
19 *
20 * @license GPL-2.0-or-later
21 */
22class ViolationMessageSerializer implements Serializer {
23
24    private function abbreviateViolationMessageKey( string $fullMessageKey ): string {
25        return substr( $fullMessageKey, strlen( ViolationMessage::MESSAGE_KEY_PREFIX ) );
26    }
27
28    /**
29     * @param ViolationMessage $object
30     * @return array
31     */
32    public function serialize( $object ): array {
33        /** @var ViolationMessage $object */
34        Assert::parameterType( ViolationMessage::class, $object, '$object' );
35
36        $arguments = $object->getArguments();
37        $serializedArguments = [];
38        foreach ( $arguments as $argument ) {
39            $serializedArguments[] = $this->serializeArgument( $argument );
40        }
41
42        return [
43            'k' => $this->abbreviateViolationMessageKey( $object->getMessageKey() ),
44            'a' => $serializedArguments,
45        ];
46    }
47
48    /**
49     * @param array $argument element of ViolationMessage::getArguments()
50     * @return array [ 't' => ViolationMessage::TYPE_*, 'v' => serialized value, 'r' => $role ]
51     */
52    private function serializeArgument( array $argument ): array {
53        $methods = [
54            ViolationMessage::TYPE_ENTITY_ID => 'serializeEntityId',
55            ViolationMessage::TYPE_ENTITY_ID_LIST => 'serializeEntityIdList',
56            ViolationMessage::TYPE_ITEM_ID_SNAK_VALUE => 'serializeItemIdSnakValue',
57            ViolationMessage::TYPE_ITEM_ID_SNAK_VALUE_LIST => 'serializeItemIdSnakValueList',
58            ViolationMessage::TYPE_DATA_VALUE => 'serializeDataValue',
59            ViolationMessage::TYPE_DATA_VALUE_TYPE => 'serializeStringByIdentity',
60            ViolationMessage::TYPE_INLINE_CODE => 'serializeStringByIdentity',
61            ViolationMessage::TYPE_CONSTRAINT_SCOPE => 'serializeContextType',
62            ViolationMessage::TYPE_CONSTRAINT_SCOPE_LIST => 'serializeContextTypeList',
63            ViolationMessage::TYPE_PROPERTY_SCOPE => 'serializeContextType',
64            ViolationMessage::TYPE_PROPERTY_SCOPE_LIST => 'serializeContextTypeList',
65            ViolationMessage::TYPE_LANGUAGE => 'serializeStringByIdentity',
66            ViolationMessage::TYPE_LANGUAGE_LIST => 'serializeStringListByIdentity',
67            ViolationMessage::TYPE_MULTILINGUAL_TEXT => 'serializeMultilingualText',
68        ];
69
70        $type = $argument['type'];
71        $value = $argument['value'];
72        $role = $argument['role'];
73
74        if ( array_key_exists( $type, $methods ) ) {
75            $method = $methods[$type];
76            $serializedValue = $this->$method( $value );
77        } else {
78            throw new InvalidArgumentException(
79                'Unknown ViolationMessage argument type ' . $type . '!'
80            );
81        }
82
83        $serialized = [
84            't' => $type,
85            'v' => $serializedValue,
86            'r' => $role,
87        ];
88
89        return $serialized;
90    }
91
92    /**
93     * @param string $string any value that shall simply be serialized to itself
94     * @return string that same value, unchanged
95     */
96    private function serializeStringByIdentity( string $string ): string {
97        return $string;
98    }
99
100    /**
101     * @param string[] $strings
102     * @return string[]
103     */
104    private function serializeStringListByIdentity( array $strings ): array {
105        Assert::parameterElementType( 'string', $strings, '$strings' );
106        return $strings;
107    }
108
109    /**
110     * @param EntityId $entityId
111     * @return string entity ID serialization
112     */
113    private function serializeEntityId( EntityId $entityId ): string {
114        return $entityId->getSerialization();
115    }
116
117    /**
118     * @param EntityId[] $entityIdList
119     * @return string[] entity ID serializations
120     */
121    private function serializeEntityIdList( array $entityIdList ): array {
122        return array_map( [ $this, 'serializeEntityId' ], $entityIdList );
123    }
124
125    /**
126     * @param ItemIdSnakValue $value
127     * @return string entity ID serialization, '::somevalue', or '::novalue'
128     * (according to EntityId::PATTERN, entity ID serializations can never begin with two colons)
129     */
130    private function serializeItemIdSnakValue( ItemIdSnakValue $value ): string {
131        switch ( true ) {
132            case $value->isValue():
133                return $this->serializeEntityId( $value->getItemId() );
134            case $value->isSomeValue():
135                return '::somevalue';
136            case $value->isNoValue():
137                return '::novalue';
138            default:
139                // @codeCoverageIgnoreStart
140                throw new LogicException(
141                    'ItemIdSnakValue should guarantee that one of is{,Some,No}Value() is true'
142                );
143                // @codeCoverageIgnoreEnd
144        }
145    }
146
147    /**
148     * @param ItemIdSnakValue[] $valueList
149     * @return string[] array of entity ID serializations, '::somevalue's or '::novalue's
150     */
151    private function serializeItemIdSnakValueList( array $valueList ): array {
152        return array_map( [ $this, 'serializeItemIdSnakValue' ], $valueList );
153    }
154
155    /**
156     * @param DataValue $dataValue
157     * @return array the data value in array form
158     */
159    private function serializeDataValue( DataValue $dataValue ): array {
160        return $dataValue->toArray();
161    }
162
163    /**
164     * @param string $contextType one of the Context::TYPE_* constants
165     * @return string the abbreviated context type
166     */
167    private function serializeContextType( string $contextType ): string {
168        switch ( $contextType ) {
169            case Context::TYPE_STATEMENT:
170                return 's';
171            case Context::TYPE_QUALIFIER:
172                return 'q';
173            case Context::TYPE_REFERENCE:
174                return 'r';
175            default:
176                // @codeCoverageIgnoreStart
177                throw new LogicException(
178                    'Unknown context type ' . $contextType
179                );
180                // @codeCoverageIgnoreEnd
181        }
182    }
183
184    /**
185     * @param string[] $contextTypeList Context::TYPE_* constants
186     * @return string[] abbreviated context types
187     */
188    private function serializeContextTypeList( array $contextTypeList ): array {
189        return array_map( [ $this, 'serializeContextType' ], $contextTypeList );
190    }
191
192    /**
193     * @param MultilingualTextValue $text
194     * @return mixed {@see MultilingualTextValue::getArrayValue}
195     */
196    private function serializeMultilingualText( MultilingualTextValue $text ) {
197        return $text->getArrayValue();
198    }
199
200}