Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.45% covered (success)
95.45%
63 / 66
78.57% covered (warning)
78.57%
11 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
LexemeContent
95.45% covered (success)
95.45%
63 / 66
78.57% covered (warning)
78.57%
11 / 14
28
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 newFromRedirect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIgnoreKeysForFilters
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getEntity
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 isCountable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getEntityHolder
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEntityRedirect
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRedirectTarget
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isValid
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getEntityPageProperties
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 getTextForSearchIndex
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
 constructAsLexemeContent
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 constructAsRedirect
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getTextForSummary
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace Wikibase\Lexeme\MediaWiki\Content;
4
5use InvalidArgumentException;
6use LogicException;
7use MediaWiki\MediaWikiServices;
8use MediaWiki\Title\Title;
9use Wikibase\DataModel\Entity\EntityRedirect;
10use Wikibase\Lexeme\Domain\Model\Lexeme;
11use Wikibase\Lexeme\Presentation\Content\LemmaTextSummaryFormatter;
12use Wikibase\Repo\Content\EntityContent;
13use Wikibase\Repo\Content\EntityHolder;
14use Wikimedia\Assert\Assert;
15
16/**
17 * TODO: Can this be split into two classes? (LexemeRedirectContent, LexemeContent)
18 *
19 * @license GPL-2.0-or-later
20 */
21class LexemeContent extends EntityContent {
22
23    public const CONTENT_MODEL_ID = 'wikibase-lexeme';
24
25    /**
26     * @var EntityHolder|null
27     */
28    private $lexemeHolder;
29
30    /**
31     * @var EntityRedirect
32     */
33    private $redirect;
34
35    /**
36     * @var Title
37     */
38    private $redirectTitle;
39
40    /**
41     * @var LemmaTextSummaryFormatter
42     */
43    private $summaryFormatter;
44
45    /**
46     * @param EntityHolder|null $lexemeHolder
47     *
48     * @throws InvalidArgumentException
49     */
50    public function __construct(
51        ?EntityHolder $lexemeHolder = null,
52        ?EntityRedirect $redirect = null,
53        ?Title $redirectTitle = null
54    ) {
55        parent::__construct( self::CONTENT_MODEL_ID );
56
57        if ( $lexemeHolder !== null && $redirect !== null ) {
58            throw new InvalidArgumentException(
59                'Cannot contain lexeme and be a redirect at the same time'
60            );
61        }
62
63        if ( $lexemeHolder !== null ) {
64            $this->constructAsLexemeContent( $lexemeHolder );
65        } elseif ( $redirect !== null ) {
66            $this->constructAsRedirect( $redirect, $redirectTitle );
67        }
68
69        $this->summaryFormatter = new LemmaTextSummaryFormatter(
70            MediaWikiServices::getInstance()->getContentLanguage()
71        );
72    }
73
74    public static function newFromRedirect( $redirect, $title ) {
75        return new self( null, $redirect, $title );
76    }
77
78    protected function getIgnoreKeysForFilters() {
79        // FIXME: This was the default list of keys as extracted form EntityContent
80        // Lexemes should probably have different keys set here but we need to know what
81        // is already being used in AbuseFilter on wikidata.org
82        // https://phabricator.wikimedia.org/T205254
83        return [
84            'language',
85            'site',
86            'type',
87            'hash',
88        ];
89    }
90
91    /**
92     * @see EntityContent::getEntity
93     *
94     * @return Lexeme
95     */
96    public function getEntity() {
97        if ( !$this->lexemeHolder ) {
98            throw new LogicException( 'This content object is empty!' );
99        }
100
101        // @phan-suppress-next-line PhanTypeMismatchReturnSuperType
102        return $this->lexemeHolder->getEntity( Lexeme::class );
103    }
104
105    /**
106     * @see EntityContent::isCountable
107     *
108     * @param bool|null $hasLinks
109     *
110     * @return bool
111     */
112    public function isCountable( $hasLinks = null ) {
113        return !$this->isRedirect() && !$this->getEntity()->isEmpty();
114    }
115
116    /**
117     * @see EntityContent::getEntityHolder
118     *
119     * @return EntityHolder|null
120     */
121    public function getEntityHolder() {
122        return $this->lexemeHolder;
123    }
124
125    public function getEntityRedirect() {
126        return $this->redirect;
127    }
128
129    public function getRedirectTarget() {
130        return $this->redirectTitle;
131    }
132
133    /**
134     * @see EntityContent::isValid
135     *
136     * @return bool
137     */
138    public function isValid() {
139        return parent::isValid()
140            && ( $this->isRedirect()
141            || $this->getEntity()->isSufficientlyInitialized() );
142    }
143
144    /**
145     * @see EntityContent::getEntityPageProperties
146     *
147     * Records the number of statements in the 'wb-claims' key.
148     * Counts all statements on the page, including statements of forms and senses.
149     *
150     * @return array A map from property names to property values.
151     */
152    public function getEntityPageProperties() {
153        $properties = parent::getEntityPageProperties();
154        $lexeme = $this->getEntity();
155
156        $count = $lexeme->getStatements()->count();
157
158        foreach ( $lexeme->getForms()->toArrayUnordered() as $form ) {
159            $count += $form->getStatements()->count();
160        }
161
162        foreach ( $lexeme->getSenses()->toArrayUnordered() as $sense ) {
163            $count += $sense->getStatements()->count();
164        }
165
166        $properties['wb-claims'] = $count;
167
168        $properties['wbl-senses'] = $lexeme->getSenses()->count();
169        $properties['wbl-forms'] = $lexeme->getForms()->count();
170
171        return $properties;
172    }
173
174    /**
175     * Make text representation of the Lexeme as list of all lemmas and form representations.
176     * @see EntityContent::getTextForSearchIndex()
177     */
178    public function getTextForSearchIndex() {
179        if ( $this->isRedirect() ) {
180            return '';
181        }
182
183        $lexeme = $this->getEntity();
184        // Note: this assumes that only one lemma per language exists
185        $terms = array_values( $lexeme->getLemmas()->toTextArray() );
186
187        foreach ( $lexeme->getForms()->toArray() as $form ) {
188            $terms = array_merge( $terms,
189                array_values( $form->getRepresentations()->toTextArray() ) );
190        }
191
192        return implode( ' ', $terms );
193    }
194
195    private function constructAsLexemeContent( EntityHolder $lexemeHolder ) {
196        Assert::parameter(
197            $lexemeHolder->getEntityType() === Lexeme::ENTITY_TYPE,
198            '$lexemeHolder',
199            '$lexemeHolder must contain a Lexeme entity'
200        );
201
202        $this->lexemeHolder = $lexemeHolder;
203    }
204
205    private function constructAsRedirect( EntityRedirect $redirect, ?Title $redirectTitle = null ) {
206        if ( $redirectTitle === null ) {
207            throw new InvalidArgumentException(
208                '$redirect and $redirectTitle must both be provided or both be empty.'
209            );
210        }
211
212        $this->redirect = $redirect;
213        $this->redirectTitle = $redirectTitle;
214    }
215
216    /**
217     * Returns a textual representation of the content suitable for use in edit summaries and log messages.
218     *
219     * @param int $maxLength maximum length of the summary text
220     * @return string
221     */
222    public function getTextForSummary( $maxLength = 250 ) {
223        if ( $this->isRedirect() ) {
224            return $this->getRedirectText();
225        }
226
227        return $this->summaryFormatter->getSummary(
228            $this->getEntity()->getLemmas(),
229            $maxLength
230        );
231    }
232}