Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
51.35% covered (warning)
51.35%
19 / 37
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
LexemeLanguageField
51.35% covered (warning)
51.35%
19 / 37
0.00% covered (danger)
0.00%
0 / 5
36.57
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getMapping
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getLanguageCode
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
7.12
 getFieldData
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getEngineHints
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2namespace Wikibase\Lexeme\Search\Elastic;
3
4use CirrusSearch\CirrusSearch;
5use CirrusSearch\Search\CirrusIndexField;
6use DataValues\StringValue;
7use SearchEngine;
8use Wikibase\DataModel\Entity\EntityDocument;
9use Wikibase\DataModel\Entity\EntityId;
10use Wikibase\DataModel\Entity\NumericPropertyId;
11use Wikibase\DataModel\Services\Lookup\EntityLookup;
12use Wikibase\DataModel\Snak\PropertyValueSnak;
13use Wikibase\DataModel\Statement\StatementListProvider;
14use Wikibase\Lexeme\Domain\Model\Lexeme;
15
16/**
17 * Lexeme language field - this contains Q-id of lexeme language.
18 */
19class LexemeLanguageField extends LexemeKeywordField {
20    public const NAME = 'lexeme_language';
21
22    /**
23     * @var EntityLookup
24     */
25    private $entityLookup;
26
27    /**
28     * @var NumericPropertyId|null
29     */
30    private $lexemeLanguageCodePropertyId;
31
32    public function __construct(
33        EntityLookup $entityLookup,
34        NumericPropertyId $lexemeLanguageCodePropertyId = null
35    ) {
36        parent::__construct();
37        $this->lexemeLanguageCodePropertyId = $lexemeLanguageCodePropertyId;
38        $this->entityLookup = $entityLookup;
39    }
40
41    /**
42     * Create mapping for Lexeme language.
43     * Two fields:
44     * - entity - Q-id of language entity
45     * - code - language code for the language
46     * @param SearchEngine $engine
47     *
48     * @return array
49     */
50    public function getMapping( SearchEngine $engine ) {
51        // Since we need a specially tuned field, we can not use
52        // standard search engine types.
53        if ( !( $engine instanceof CirrusSearch ) ) {
54            // For now only Cirrus/Elastic is supported
55            return [];
56        }
57        return [
58            'type' => 'object',
59            'properties' => [
60                // Both subfields are keywords
61                'entity' => parent::getMapping( $engine ),
62                'code' => parent::getMapping( $engine ),
63            ],
64        ];
65    }
66
67    /**
68     * Extract language code from language entity
69     * @param EntityId $languageId The ID of the language entity
70     * @return null|string
71     */
72    private function getLanguageCode( EntityId $languageId ) {
73        if ( !$this->lexemeLanguageCodePropertyId ) {
74            return null;
75        }
76        $langEntity = $this->entityLookup->getEntity( $languageId );
77        if ( !$langEntity || !( $langEntity instanceof StatementListProvider ) ) {
78            return null;
79        }
80        $langCodes = $langEntity->getStatements()->getByPropertyId( $this->lexemeLanguageCodePropertyId );
81        if ( $langCodes->isEmpty() ) {
82            return null;
83        }
84        // if there are more than one code, take the first one.
85        $codeSnak = $langCodes->getAllSnaks()[0];
86        if ( !( $codeSnak instanceof PropertyValueSnak ) ) {
87            return null;
88        }
89        $value = $codeSnak->getDataValue();
90        if ( !( $value instanceof StringValue ) ) {
91            return null;
92        }
93        return $value->getValue();
94    }
95
96    /**
97     * @param EntityDocument $entity
98     *
99     * @return mixed Get the value of the field to be indexed when a page/document
100     *               is indexed. This might be an array with nested data, if the field
101     *               is defined with nested type or an int or string for simple field types.
102     */
103    public function getFieldData( EntityDocument $entity ) {
104        if ( !( $entity instanceof Lexeme ) ) {
105            return [];
106        }
107        /**
108         * @var Lexeme $entity
109         */
110        $language = $entity->getLanguage();
111        return [
112            'entity' => $language->getSerialization(),
113            'code' => $this->getLanguageCode( $language ),
114        ];
115    }
116
117    /**
118     * Set engine hints.
119     * Specifically, sets noop hint so that forms would be compared
120     * as arrays and changes in language parts would be processed correctly.
121     * @param SearchEngine $engine
122     * @return array
123     */
124    public function getEngineHints( SearchEngine $engine ) {
125        if ( !( $engine instanceof CirrusSearch ) ) {
126            // For now only Cirrus/Elastic is supported
127            return [];
128        }
129        return [ CirrusIndexField::NOOP_HINT => "equals" ];
130    }
131
132}