Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.73% covered (warning)
81.73%
85 / 104
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
LexemeView
81.73% covered (warning)
81.73%
85 / 104
77.78% covered (warning)
77.78%
7 / 9
14.03
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
 getContent
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getMainHtml
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getLexemeHeader
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 getSideHtml
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTitleHtml
5.26% covered (danger)
5.26%
1 / 19
0.00% covered (danger)
0.00%
0 / 1
17.60
 getLocalizedMessage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderLemmaWidget
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
1
 renderLanguageAndLexicalCategoryWidget
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Wikibase\Lexeme\Presentation\View;
4
5use InvalidArgumentException;
6use MediaWiki\Message\Message;
7use Wikibase\DataModel\Entity\EntityDocument;
8use Wikibase\DataModel\Services\EntityId\EntityIdFormatter;
9use Wikibase\DataModel\Term\Term;
10use Wikibase\Lexeme\Domain\Model\Lexeme;
11use Wikibase\Lexeme\Presentation\Formatters\LexemeTermFormatter;
12use Wikibase\Lexeme\Presentation\View\Template\VueTemplates;
13use Wikibase\View\EntityView;
14use Wikibase\View\LanguageDirectionalityLookup;
15use Wikibase\View\StatementSectionsView;
16use Wikibase\View\Template\TemplateFactory;
17use Wikibase\View\ViewContent;
18use Wikimedia\Assert\Assert;
19use WMDE\VueJsTemplating\Templating;
20
21/**
22 * Class for creating HTML views for Lexeme instances.
23 *
24 * @license GPL-2.0-or-later
25 * @author Amir Sarabadani <ladsgroup@gmail.com>
26 */
27class LexemeView extends EntityView {
28
29    /**
30     * @var FormsView
31     */
32    private $formsView;
33
34    /**
35     * @var SensesView
36     */
37    private $sensesView;
38
39    /**
40     * @var StatementSectionsView
41     */
42    private $statementSectionsView;
43
44    /**
45     * @var EntityIdFormatter
46     */
47    private $idFormatter;
48
49    /**
50     * @var LexemeTermFormatter
51     */
52    private $lemmaFormatter;
53
54    /**
55     * @param TemplateFactory $templateFactory
56     * @param LanguageDirectionalityLookup $languageDirectionalityLookup
57     * @param string $languageCode
58     * @param FormsView $formsView
59     * @param SensesView $sensesView
60     * @param StatementSectionsView $statementSectionsView
61     * @param LexemeTermFormatter $lemmaFormatter
62     * @param EntityIdFormatter $idFormatter
63     */
64    public function __construct(
65        TemplateFactory $templateFactory,
66        LanguageDirectionalityLookup $languageDirectionalityLookup,
67        $languageCode,
68        FormsView $formsView,
69        SensesView $sensesView,
70        StatementSectionsView $statementSectionsView,
71        LexemeTermFormatter $lemmaFormatter,
72        EntityIdFormatter $idFormatter
73    ) {
74        parent::__construct(
75            $templateFactory,
76            $languageDirectionalityLookup,
77            $languageCode
78        );
79
80        $this->formsView = $formsView;
81        $this->sensesView = $sensesView;
82        $this->statementSectionsView = $statementSectionsView;
83        $this->idFormatter = $idFormatter;
84        $this->lemmaFormatter = $lemmaFormatter;
85    }
86
87    /**
88     * Builds and returns the main content representing a whole Lexeme
89     *
90     * @param EntityDocument $entity the entity to render
91     * @param int|null $revision the revision of the entity to render
92     *
93     * @return ViewContent
94     */
95    public function getContent( EntityDocument $entity, $revision = null ): ViewContent {
96        return new ViewContent(
97            $this->renderEntityView( $entity )
98        );
99    }
100
101    /**
102     * @see EntityView::getMainHtml
103     *
104     * @param EntityDocument $entity
105     *
106     * @throws InvalidArgumentException if the entity type does not match.
107     * @return string HTML
108     */
109    protected function getMainHtml( EntityDocument $entity ) {
110        /** @var Lexeme $entity */
111        Assert::parameterType( Lexeme::class, $entity, '$entity' );
112        '@phan-var Lexeme $entity';
113
114        $html = $this->getLexemeHeader( $entity )
115            . $this->templateFactory->render( 'wikibase-toc' )
116            . $this->statementSectionsView->getHtml( $entity->getStatements() )
117            . $this->sensesView->getHtml( $entity->getSenses() )
118            . $this->formsView->getHtml( $entity->getForms() );
119
120        return $html;
121    }
122
123    /**
124     * @param Lexeme $entity
125     * @return string HTML
126     */
127    private function getLexemeHeader( Lexeme $entity ) {
128        $id = '';
129        if ( $entity->getId() ) {
130            $id = htmlspecialchars(
131                $this->getLocalizedMessage( 'parentheses', [ $entity->getId()->getSerialization() ] )
132            );
133        }
134
135        $lemmaWidget = $this->renderLemmaWidget( $entity );
136        $languageAndCategory = $this->renderLanguageAndLexicalCategoryWidget( $entity );
137
138        return <<<HTML
139            <div id="wb-lexeme-header" class="wb-lexeme-header">
140                <div id="wb-lexeme-header-lemmas">
141                    <div class="wb-lexeme-header_id">$id</div>
142                    <div class="wb-lexeme-header_lemma-widget">
143                        $lemmaWidget
144                    </div>
145                </div>
146                $languageAndCategory
147            </div>
148HTML;
149    }
150
151    /**
152     * @see EntityView::getSideHtml
153     *
154     * @param EntityDocument $entity
155     *
156     * @return string HTML
157     */
158    protected function getSideHtml( EntityDocument $entity ) {
159        return '';
160    }
161
162    /**
163     * @param EntityDocument $entity
164     *
165     * @return string
166     */
167    public function getTitleHtml( EntityDocument $entity ) {
168        /** @var Lexeme $entity */
169        Assert::parameterType( Lexeme::class, $entity, '$entity' );
170        '@phan-var Lexeme $entity';
171        $isEmpty = true;
172        $idInParenthesesHtml = '';
173        $labelHtml = '';
174
175        if ( $entity->getId() !== null ) {
176            $id = $entity->getId()->getSerialization();
177            $isEmpty = false;
178            $idInParenthesesHtml = htmlspecialchars(
179                $this->getLocalizedMessage( 'parentheses', [ $id ] )
180            );
181
182            $labelHtml = $this->lemmaFormatter->format( $entity->getLemmas() );
183        }
184
185        $title = $isEmpty ? htmlspecialchars(
186            $this->getLocalizedMessage( 'wikibase-label-empty' ) ) : $labelHtml;
187
188        return $this->templateFactory->render(
189            'wikibase-title',
190            $isEmpty ? 'wb-empty' : '',
191            $title,
192            $idInParenthesesHtml
193        );
194    }
195
196    /**
197     * @param string $key
198     * @param array $params
199     *
200     * @return string Plain text
201     */
202    private function getLocalizedMessage( $key, array $params = [] ) {
203        return ( new Message( $key, $params ) )->inLanguage( $this->languageCode )->text();
204    }
205
206    /**
207     * @return string
208     */
209    private function renderLemmaWidget( Lexeme $lexeme ) {
210        $templating = new Templating();
211        $template = file_get_contents( __DIR__ . VueTemplates::LEMMA );
212
213        $lemmas = array_map(
214            static function ( Term $lemma ) {
215                return [ 'value' => $lemma->getText(), 'language' => $lemma->getLanguageCode() ];
216            },
217            iterator_to_array( $lexeme->getLemmas() )
218        );
219
220        $result = $templating->render(
221            $template,
222            [
223                'isInitialized' => false,
224                'inEditMode' => false,
225                'isSaving' => false,
226                'lemmaList' => $lemmas,
227                'isUnsaveable' => true,
228            ],
229            [
230                'message' => function ( $key ) {
231                    return $this->getLocalizedMessage( $key );
232                },
233            ]
234        );
235
236        return '<div id="lemmas-widget">'
237            . $result
238            . '</div>';
239    }
240
241    /**
242     * @param Lexeme $lexeme
243     * @return string
244     */
245    private function renderLanguageAndLexicalCategoryWidget( Lexeme $lexeme ) {
246        $templating = new Templating();
247        $categoryTemplate = file_get_contents( __DIR__ . VueTemplates::CATEGORY_WIDGET );
248
249        $languageId = $lexeme->getLanguage();
250        $lexicalCategoryId = $lexeme->getLexicalCategory();
251
252        $result = $templating->render(
253            $categoryTemplate,
254            [
255                'isInitialized' => false,
256                'inEditMode' => false,
257                'isSaving' => false,
258                'formattedLanguage' => $this->idFormatter->formatEntityId( $languageId ),
259                'language' => $languageId->getSerialization(),
260                'formattedLexicalCategory' => $this->idFormatter->formatEntityId(
261                    $lexicalCategoryId
262                ),
263                'lexicalCategory' => $lexicalCategoryId->getSerialization(),
264            ],
265            [
266                'message' => function ( $key ) {
267                    return $this->getLocalizedMessage( $key );
268                },
269            ]
270        );
271
272        return '<div>' . $result . '</div>';
273    }
274
275}