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( ?EntityRedirect $redirect, ?Title $title ): self {
75        return new self( null, $redirect, $title );
76    }
77
78    protected function getIgnoreKeysForFilters(): array {
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    /** @inheritDoc */
126    public function getEntityRedirect() {
127        return $this->redirect;
128    }
129
130    /** @inheritDoc */
131    public function getRedirectTarget() {
132        return $this->redirectTitle;
133    }
134
135    /**
136     * @see EntityContent::isValid
137     *
138     * @return bool
139     */
140    public function isValid() {
141        return parent::isValid()
142            && ( $this->isRedirect()
143            || $this->getEntity()->isSufficientlyInitialized() );
144    }
145
146    /**
147     * @see EntityContent::getEntityPageProperties
148     *
149     * Records the number of statements in the 'wb-claims' key.
150     * Counts all statements on the page, including statements of forms and senses.
151     *
152     * @return array A map from property names to property values.
153     */
154    public function getEntityPageProperties() {
155        $properties = parent::getEntityPageProperties();
156        $lexeme = $this->getEntity();
157
158        $count = $lexeme->getStatements()->count();
159
160        foreach ( $lexeme->getForms()->toArrayUnordered() as $form ) {
161            $count += $form->getStatements()->count();
162        }
163
164        foreach ( $lexeme->getSenses()->toArrayUnordered() as $sense ) {
165            $count += $sense->getStatements()->count();
166        }
167
168        $properties['wb-claims'] = $count;
169
170        $properties['wbl-senses'] = $lexeme->getSenses()->count();
171        $properties['wbl-forms'] = $lexeme->getForms()->count();
172
173        return $properties;
174    }
175
176    /**
177     * Make text representation of the Lexeme as list of all lemmas and form representations.
178     * @see EntityContent::getTextForSearchIndex()
179     *
180     * @inheritDoc
181     */
182    public function getTextForSearchIndex() {
183        if ( $this->isRedirect() ) {
184            return '';
185        }
186
187        $lexeme = $this->getEntity();
188        // Note: this assumes that only one lemma per language exists
189        $terms = array_values( $lexeme->getLemmas()->toTextArray() );
190
191        foreach ( $lexeme->getForms()->toArray() as $form ) {
192            $terms = array_merge( $terms,
193                array_values( $form->getRepresentations()->toTextArray() ) );
194        }
195
196        return implode( ' ', $terms );
197    }
198
199    private function constructAsLexemeContent( EntityHolder $lexemeHolder ) {
200        Assert::parameter(
201            $lexemeHolder->getEntityType() === Lexeme::ENTITY_TYPE,
202            '$lexemeHolder',
203            '$lexemeHolder must contain a Lexeme entity'
204        );
205
206        $this->lexemeHolder = $lexemeHolder;
207    }
208
209    private function constructAsRedirect( EntityRedirect $redirect, ?Title $redirectTitle = null ) {
210        if ( $redirectTitle === null ) {
211            throw new InvalidArgumentException(
212                '$redirect and $redirectTitle must both be provided or both be empty.'
213            );
214        }
215
216        $this->redirect = $redirect;
217        $this->redirectTitle = $redirectTitle;
218    }
219
220    /**
221     * Returns a textual representation of the content suitable for use in edit summaries and log messages.
222     *
223     * @param int $maxLength maximum length of the summary text
224     * @return string
225     */
226    public function getTextForSummary( $maxLength = 250 ) {
227        if ( $this->isRedirect() ) {
228            return $this->getRedirectText();
229        }
230
231        return $this->summaryFormatter->getSummary(
232            $this->getEntity()->getLemmas(),
233            $maxLength
234        );
235    }
236}