Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.96% covered (success)
97.96%
96 / 98
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
FormsView
97.96% covered (success)
97.96%
96 / 98
71.43% covered (warning)
71.43%
5 / 7
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getHtml
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 getFormHtml
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
1
 getSortedGrammaticalFeatures
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
4.00
 renderRepresentationWidget
95.65% covered (success)
95.65%
22 / 23
0.00% covered (danger)
0.00%
0 / 1
1
 getGrammaticalFeatureHtml
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStatementSectionHtml
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Wikibase\Lexeme\Presentation\View;
4
5use Wikibase\DataModel\Entity\ItemId;
6use Wikibase\DataModel\Services\EntityId\EntityIdFormatter;
7use Wikibase\DataModel\Term\Term;
8use Wikibase\Lexeme\Domain\Model\Form;
9use Wikibase\Lexeme\Domain\Model\FormSet;
10use Wikibase\Lexeme\Presentation\View\Template\LexemeTemplateFactory;
11use Wikibase\Lexeme\Presentation\View\Template\VueTemplates;
12use Wikibase\Lib\Store\ItemOrderProvider;
13use Wikibase\View\LocalizedTextProvider;
14use Wikibase\View\StatementGroupListView;
15use WMDE\VueJsTemplating\Templating;
16
17/**
18 * @license GPL-2.0-or-later
19 * @author Thiemo Kreuz
20 */
21class FormsView {
22
23    /**
24     * @var LocalizedTextProvider
25     */
26    private $textProvider;
27
28    /**
29     * @var LexemeTemplateFactory
30     */
31    private $templateFactory;
32
33    /**
34     * @var EntityIdFormatter
35     */
36    private $entityIdFormatter;
37
38    /**
39     * @var StatementGroupListView
40     */
41    private $statementGroupListView;
42
43    /**
44     * @var ItemOrderProvider
45     */
46    private $grammaticalFeaturesOrderProvider;
47
48    public function __construct(
49        LocalizedTextProvider $textProvider,
50        LexemeTemplateFactory $templateFactory,
51        EntityIdFormatter $entityIdFormatter,
52        StatementGroupListView $statementGroupListView,
53        ItemOrderProvider $grammaticalFeaturesOrderProvider
54    ) {
55        $this->textProvider = $textProvider;
56        $this->templateFactory = $templateFactory;
57        $this->entityIdFormatter = $entityIdFormatter;
58        $this->statementGroupListView = $statementGroupListView;
59        $this->grammaticalFeaturesOrderProvider = $grammaticalFeaturesOrderProvider;
60    }
61
62    /**
63     * @param FormSet $forms
64     *
65     * @return string HTML
66     */
67    public function getHtml( FormSet $forms ) {
68        $html = '<div class="wikibase-lexeme-forms-section">';
69        $html .= '<h2 class="wb-section-heading section-heading" id="forms">'
70            . htmlspecialchars( $this->textProvider->get( 'wikibaselexeme-header-forms' ) )
71            . '</h2>';
72
73        $html .= '<div class="wikibase-lexeme-forms ">';
74        foreach ( $forms->toArray() as $form ) {
75            $html .= $this->getFormHtml( $form );
76        }
77        $html .= '</div>'; // wikibase-lexeme-forms
78        // @phan-suppress-next-line PhanPluginDuplicateAdjacentStatement
79        $html .= '</div>'; // wikibase-lexeme-forms-section
80        return $html;
81    }
82
83    /**
84     * @param Form $form
85     *
86     * @return string HTML
87     */
88    private function getFormHtml( Form $form ) {
89        $grammaticalFeaturesHtml = $this->templateFactory->render(
90            'wikibase-lexeme-form-grammatical-features',
91            [
92                htmlspecialchars(
93                    $this->textProvider->get( 'wikibaselexeme-form-grammatical-features' ),
94                    ENT_QUOTES,
95                    'UTF-8',
96                    false
97                ),
98                implode(
99                    // Escape HTML without double escaping entities, {@see Message::escaped}
100                    htmlspecialchars( $this->textProvider->get( 'comma-separator' ), ENT_QUOTES, 'UTF-8', false ),
101                    array_map(
102                        function ( ItemId $id ) {
103                            return '<span>' . $this->getGrammaticalFeatureHtml( $id ) . '</span>';
104                        },
105                        $this->getSortedGrammaticalFeatures( $form )
106                    )
107                ),
108            ]
109        );
110
111        return $this->templateFactory->render( 'wikibase-lexeme-form', [
112            htmlspecialchars( $form->getId()->getSerialization() ),
113            $this->renderRepresentationWidget( $form ),
114            $grammaticalFeaturesHtml,
115            $this->getStatementSectionHtml( $form ),
116            // Anchor separated from ID to avoid issue with front-end rendering
117            htmlspecialchars( $form->getId()->getIdSuffix() ),
118        ] );
119    }
120
121    /**
122     * Return a list of grammatical features by a specific order,
123     * decided by the list maintained in the wikipage
124     * MediaWiki:WikibaseLexeme-SortedGrammaticalFeatures
125     *
126     * @param Form $form
127     *
128     * @return ItemId[]
129     */
130    private function getSortedGrammaticalFeatures( Form $form ): array {
131        $grammaticalFeaturesItemIds = $form->getGrammaticalFeatures();
132        $grammaticalFeaturesOrder = $this->grammaticalFeaturesOrderProvider->getItemOrder();
133
134        if ( $grammaticalFeaturesItemIds === [] ) {
135            return [];
136        }
137
138        $sortedGrammaticalFeatures = [];
139        $unsortedGrammaticalFeatures = [];
140
141        foreach ( $grammaticalFeaturesItemIds as $grammaticalFeatureItemId ) {
142            $key = $grammaticalFeatureItemId->getSerialization();
143            $grammaticalFeaturePosition = $grammaticalFeaturesOrder[ $key ] ?? null;
144            if ( $grammaticalFeaturePosition !== null ) {
145                $sortedGrammaticalFeatures[ $grammaticalFeaturePosition ] = $grammaticalFeatureItemId;
146            } else {
147                $unsortedGrammaticalFeatures[] = $grammaticalFeatureItemId;
148            }
149        }
150        ksort( $sortedGrammaticalFeatures, SORT_NUMERIC );
151        // sort new grammatical features numerically
152        usort( $unsortedGrammaticalFeatures, static function ( ItemId $a, ItemId $b ) {
153            return strcmp( $a->getSerialization(), $b->getSerialization() );
154        } );
155        $sortedGrammaticalFeatures = array_merge( $sortedGrammaticalFeatures, $unsortedGrammaticalFeatures );
156        return $sortedGrammaticalFeatures;
157    }
158
159    /**
160     * @return string
161     */
162    private function renderRepresentationWidget( Form $form ) {
163        $templating = new Templating();
164        $representationsVueTemplate = file_get_contents( __DIR__ . VueTemplates::REPRESENTATIONS );
165
166        $representations = array_map(
167            static function ( Term $r ) {
168                return [ 'value' => $r->getText(), 'language' => $r->getLanguageCode() ];
169            },
170            iterator_to_array( $form->getRepresentations() )
171        );
172
173        $result = $templating->render(
174            $representationsVueTemplate,
175            [
176                'inEditMode' => false,
177                'representations' => $representations,
178            ],
179            [
180                'message' => function ( $key ) {
181                    return $this->textProvider->get( $key );
182                },
183            ]
184        );
185
186        return '<div class="form-representations">'
187            . $result
188            . '</div>';
189    }
190
191    /**
192     * @param ItemId $id
193     *
194     * @return string HTML
195     */
196    private function getGrammaticalFeatureHtml( ItemId $id ) {
197        return $this->entityIdFormatter->formatEntityId( $id );
198    }
199
200    /**
201     * @param Form $form
202     *
203     * @return string HTML
204     */
205    private function getStatementSectionHtml( Form $form ) {
206        $headerText = htmlspecialchars(
207            $this->textProvider->get(
208                'wikibaselexeme-statementsection-statements-about-form',
209                [ $form->getId()->getSerialization() ]
210            )
211        );
212
213        $statementHeader = <<<HTML
214<h2 class="wb-section-heading section-heading wikibase-statements" dir="auto">
215    $headerText
216</h2>
217HTML;
218
219        $statementSection = $this->statementGroupListView->getHtml(
220            $form->getStatements()->toArray(), $form->getId()->getIdSuffix()
221        );
222        return $statementHeader . $statementSection;
223    }
224
225}