Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialListMissingLabels
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 7
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParameters
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
56
 execute
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
2
 getHeaderTitle
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getHeaderForm
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * WikiLambda Special:ListMissingLabels page
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\Special;
12
13use MediaWiki\Extension\WikiLambda\Fields\HTMLZLanguageSelectField;
14use MediaWiki\Extension\WikiLambda\Fields\HTMLZTypeSelectField;
15use MediaWiki\Extension\WikiLambda\Pagers\BasicZObjectPager;
16use MediaWiki\Extension\WikiLambda\Registry\ZLangRegistry;
17use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
18use MediaWiki\Extension\WikiLambda\ZObjectStore;
19use MediaWiki\Extension\WikiLambda\ZObjectUtils;
20use MediaWiki\HTMLForm\HTMLForm;
21use MediaWiki\Languages\LanguageFallback;
22use MediaWiki\SpecialPage\SpecialPage;
23
24class SpecialListMissingLabels extends SpecialPage {
25
26    private ZObjectStore $zObjectStore;
27    private LanguageFallback $languageFallback;
28    private ZLangRegistry $langRegistry;
29
30    /**
31     * @param ZObjectStore $zObjectStore
32     * @param LanguageFallback $languageFallback
33     */
34    public function __construct( ZObjectStore $zObjectStore, LanguageFallback $languageFallback ) {
35        parent::__construct( 'ListMissingLabels' );
36        $this->zObjectStore = $zObjectStore;
37        $this->languageFallback = $languageFallback;
38        $this->langRegistry = ZLangRegistry::singleton();
39    }
40
41    /**
42     * @inheritDoc
43     */
44    protected function getGroupName() {
45        // Triggers use of message specialpages-group-wikilambda
46        return 'wikilambda';
47    }
48
49    /**
50     * @inheritDoc
51     */
52    public function getDescription() {
53        return $this->msg( 'wikilambda-special-missinglabels' );
54    }
55
56    /**
57     * Get and validate SpecialPage parameters from subpage and url
58     *
59     * @param string $subpage
60     * @return array - type ZID, lang ZID, excludePreDefined
61     */
62    private function getParameters( $subpage ) {
63        // Get language from Request.
64        // * Can be empty string, valid or invalid Zid
65        // * Default: User language
66        $langZid = $this->getRequest()->getText( 'language' );
67        if ( ( !$langZid ) || !ZObjectUtils::isValidZObjectReference( $langZid ) ) {
68            $langCode = $this->getLanguage()->getCode();
69            $langZid = $this->langRegistry->getLanguageZidFromCode( $langCode );
70        }
71
72        // Get type from subpage; overwrite with value from Request.
73        // * subpage can be empty string or NULL or valid/invalid string
74        // * requestType can be empty string or valid/invalid string
75        // Default: Z8/Function
76        $requestType = $this->getRequest()->getText( 'type' );
77        if ( $requestType && ZObjectUtils::isValidZObjectReference( $requestType ) ) {
78            $type = $requestType;
79        } else {
80            $type = $subpage && ZObjectUtils::isValidZObjectReference( $subpage ) ?
81                $subpage : ZTypeRegistry::Z_FUNCTION;
82        }
83
84        $excludePreDefined = $this->getRequest()->getBool( 'excludePreDefined' );
85
86        return [ $type, $langZid, $excludePreDefined ];
87    }
88
89    /**
90     * @inheritDoc
91     */
92    public function execute( $subpage ) {
93        // Get and validate page parameters
94        [ $type, $langZid, $excludePreDefined ] = $this->getParameters( $subpage );
95
96        // Set headers
97        $this->setHeaders();
98        $this->outputHeader( 'wikilambda-special-missinglabels-summary' );
99
100        // Set output
101        $output = $this->getOutput();
102        $output->enableOOUI();
103        $output->addModuleStyles( [ 'mediawiki.special' ] );
104
105        // TODO (T300519): Make this help page.
106        $this->addHelpLink( 'Help:Wikifunctions/Missing labels' );
107
108        // Get list of fallback language Zids
109        $languageZids = $this->langRegistry->getListOfFallbackLanguageZids(
110            $this->languageFallback,
111            $this->getLanguage()->getCode()
112        );
113
114        // Add selected language at the start of the array; this way
115        // we will identify objects with missing label in langZid by
116        // checking that the preferred label is not in langZid.
117        // The label displayed in the list will be then the one in the
118        // user language or its closes fallback. Also, remove duplicates
119        // in case the selected language is the same as user language.
120        array_unshift( $languageZids, $langZid );
121        $languageZids = array_unique( $languageZids );
122
123        // Build BasicZObjectPager for the given filters
124        $filters = [
125            'type' => $type,
126            'missing_language' => $langZid
127        ];
128        $pager = new BasicZObjectPager(
129            $this->getContext(),
130            $this->zObjectStore,
131            $languageZids,
132            null,
133            $excludePreDefined,
134            $filters
135        );
136
137        // Add the header form
138        $output->addHTML( $this->getHeaderForm( $type, $langZid ) );
139
140        // Add the top pagination controls
141        $output->addHTML( $pager->getNavigationBar() );
142        // Add the item list body
143        $output->addWikiTextAsInterface( $pager->getBody() );
144        // Add the bottom pagination controls
145        $output->addHTML( $pager->getNavigationBar() );
146
147        // Add bottom pagination controls
148        $output->addWikiTextAsInterface( $pager->getBottomLinks() );
149    }
150
151    /**
152     * Render the header for listing ZObjects by a specific type
153     * with missing labels in the given language.
154     *
155     * @param string $typeZid - The type of ZObjects being listed.
156     * @param string $langZid - The selected language Zid.
157     * @return string - The text for the header.
158     */
159    private function getHeaderTitle( $typeZid, $langZid ) {
160        $typeLabel = $this->zObjectStore->fetchZObjectLabel( $typeZid, $this->getLanguage()->getCode() );
161        $langLabel = $this->zObjectStore->fetchZObjectLabel( $langZid, $this->getLanguage()->getCode() );
162        return $this->msg( 'wikilambda-special-missinglabels-for-type' )
163            ->rawParams( htmlspecialchars( $typeLabel ), htmlspecialchars( $typeZid ), htmlspecialchars( $langLabel ) )
164            ->text();
165    }
166
167    /**
168     * Build the form to place at the head of the Special page,
169     * with a selector field for ZTypes and another for ZLanguages.
170     *
171     * @param string $typeZid
172     * @param string $langZid
173     * @return string
174     */
175    public function getHeaderForm( $typeZid, $langZid ) {
176        $formHeader = $this->getHeaderTitle( $typeZid, $langZid );
177        $formDescriptor = [
178            'type' => [
179                'label' => 'Type',
180                'class' => HTMLZTypeSelectField::class,
181                'name' => 'type',
182                'default' => $typeZid
183            ],
184            'language' => [
185                'label' => 'Language',
186                'class' => HTMLZLanguageSelectField::class,
187                'name' => 'language',
188                'default' => $langZid
189            ],
190            'excludePreDefined' => [
191                'type' => 'check',
192                'label' => $this->msg( 'wikilambda-special-objectsbytype-form-excludepredefined' )->text(),
193                'name' => 'excludePreDefined',
194                'default' => false
195            ]
196        ];
197
198        $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
199            ->setWrapperLegend( $formHeader )
200            ->setCollapsibleOptions( true )
201            ->setMethod( 'get' );
202        return $htmlForm->prepareForm()->getHTML( false );
203    }
204}