Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.86% covered (success)
98.86%
87 / 88
85.71% covered (warning)
85.71%
6 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialEntitiesWithoutPage
98.86% covered (success)
98.86%
87 / 88
85.71% covered (warning)
85.71%
6 / 7
19
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 prepareArguments
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
7
 getLanguageOptions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 setForm
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
4
 getResult
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getTitleForNavigation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Wikibase\Search\Elastic;
4
5use HTMLForm;
6use MediaWiki\Title\Title;
7use Wikibase\Lib\ContentLanguages;
8use Wikibase\Lib\LanguageNameLookup;
9use Wikibase\Lib\Store\EntityNamespaceLookup;
10use Wikibase\Repo\Specials\SpecialWikibaseQueryPage;
11
12/**
13 * Base page for pages listing entities without a specific value.
14 *
15 * @license GPL-2.0-or-later
16 * @author Thomas Pellissier Tanon
17 * @author Bene* < benestar.wikimedia@gmail.com >
18 * @author Thiemo Kreuz
19 */
20class SpecialEntitiesWithoutPage extends SpecialWikibaseQueryPage {
21
22    /**
23     * @var string Language code as requested by the user.
24     */
25    private $requestedLanguageCode = '';
26
27    /**
28     * @var string|null Entity type identifier as requested by the user.
29     */
30    private $requestedEntityType = '';
31
32    /**
33     * @var string One of the TermIndexEntry::TYPE_... constants, provided on construction time.
34     */
35    private $termType;
36
37    /**
38     * @var string
39     */
40    private $legendMsg;
41
42    /**
43     * @var string[] List of entity type identifiers the special page should accept, provided on
44     *  construction time.
45     */
46    private $acceptableEntityTypes;
47
48    /**
49     * @var ContentLanguages
50     */
51    private $termsLanguages;
52
53    /**
54     * @var LanguageNameLookup
55     */
56    private $languageNameLookup;
57
58    /**
59     * @var EntityNamespaceLookup
60     */
61    private $entityNamespaceLookup;
62
63    /**
64     * @param string $name
65     * @param string $termType One of the TermIndexEntry::TYPE_... constants.
66     * @param string $legendMsg
67     * @param string[] $acceptableEntityTypes
68     * @param ContentLanguages $termsLanguages
69     * @param LanguageNameLookup $languageNameLookup
70     * @param EntityNamespaceLookup $entityNamespaceLookup
71     */
72    public function __construct(
73        $name,
74        $termType,
75        $legendMsg,
76        array $acceptableEntityTypes,
77        ContentLanguages $termsLanguages,
78        LanguageNameLookup $languageNameLookup,
79        EntityNamespaceLookup $entityNamespaceLookup
80    ) {
81        parent::__construct( $name );
82
83        $this->termType = $termType;
84        $this->legendMsg = $legendMsg;
85        $this->acceptableEntityTypes = $acceptableEntityTypes;
86        $this->termsLanguages = $termsLanguages;
87        $this->languageNameLookup = $languageNameLookup;
88        $this->entityNamespaceLookup = $entityNamespaceLookup;
89    }
90
91    /**
92     * @see \Wikibase\Repo\Specials\SpecialWikibasePage::execute
93     *
94     * @param string|null $subPage
95     */
96    public function execute( $subPage ) {
97        parent::execute( $subPage );
98
99        $this->prepareArguments( $subPage );
100        $this->setForm();
101
102        if ( $this->requestedLanguageCode !== '' && $this->requestedEntityType !== '' ) {
103            $this->showQuery(
104                [],
105                $this->requestedLanguageCode . '/' . $this->requestedEntityType
106            );
107        }
108    }
109
110    /**
111     * Prepare the arguments
112     *
113     * @param string|null $subPage
114     */
115    private function prepareArguments( $subPage ) {
116        $this->requestedLanguageCode = '';
117        $this->requestedEntityType = '';
118
119        if ( $subPage !== null ) {
120            $parts = explode( '/', $subPage, 2 );
121            $this->requestedLanguageCode = $parts[0];
122            if ( isset( $parts[1] ) ) {
123                $this->requestedEntityType = $parts[1];
124            }
125        }
126
127        $request = $this->getRequest();
128        $this->requestedLanguageCode = $request->getText( 'language', $this->requestedLanguageCode );
129        $this->requestedEntityType = $request->getText( 'type', $this->requestedEntityType );
130
131        if ( $this->requestedLanguageCode !== ''
132            && !$this->termsLanguages->hasLanguage( $this->requestedLanguageCode )
133        ) {
134            $this->showErrorHTML( $this->msg(
135                'wikibasecirrus-entitieswithoutlabel-invalid-language',
136                wfEscapeWikiText( $this->requestedLanguageCode )
137            )->parse() );
138            $this->requestedLanguageCode = '';
139        }
140
141        if ( $this->requestedEntityType !== ''
142            && !in_array( $this->requestedEntityType, $this->acceptableEntityTypes )
143        ) {
144            $this->showErrorHTML( $this->msg(
145                'wikibasecirrus-entitieswithoutlabel-invalid-type',
146                wfEscapeWikiText( $this->requestedEntityType )
147            )->parse() );
148            $this->requestedEntityType = '';
149        }
150    }
151
152    /**
153     * Return options for the language input field.
154     *
155     * @return string[]
156     */
157    private function getLanguageOptions() {
158        $options = [];
159
160        foreach ( $this->termsLanguages->getLanguages() as $languageCode ) {
161            $languageName = $this->languageNameLookup->getNameForTerms( $languageCode );
162            $options["$languageName ($languageCode)"] = $languageCode;
163        }
164
165        return $options;
166    }
167
168    /**
169     * Build the HTML form
170     */
171    private function setForm() {
172        $entityTypeOptions = [];
173        foreach ( $this->acceptableEntityTypes as $type ) {
174            // Messages:
175            // wikibasecirrus-entity-item
176            // wikibasecirrus-entity-property
177            $msg = $this->msg( 'wikibasecirrus-entity-' . $type );
178            $text = $msg->isDisabled() ? $type : $msg->text();
179            $entityTypeOptions[$text] = $type;
180        }
181
182        $formDescriptor = [
183            'language' => [
184                'name' => 'language',
185                'default' => $this->requestedLanguageCode,
186                'type' => 'combobox',
187                'options' => $this->getLanguageOptions(),
188                'cssclass' => 'wb-language-suggester',
189                'id' => 'wb-entitieswithoutpage-language',
190                'label-message' => 'wikibasecirrus-entitieswithoutlabel-label-language'
191            ],
192            'type' => [
193                'name' => 'type',
194                'options' => $entityTypeOptions,
195                'default' => $this->requestedEntityType ?: reset( $this->acceptableEntityTypes ),
196                'type' => 'select',
197                'id' => 'wb-entitieswithoutpage-type',
198                'label-message' => 'wikibasecirrus-entitieswithoutlabel-label-type'
199            ],
200            'submit' => [
201                'name' => '',
202                'default' => $this->msg( 'wikibasecirrus-entitieswithoutlabel-submit' )->text(),
203                'type' => 'submit',
204                'id' => 'wikibasecirrus-entitieswithoutpage-submit',
205            ]
206        ];
207
208        HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
209            ->setId( 'wb-entitieswithoutpage-form' )
210            ->setMethod( 'get' )
211            ->setWrapperLegendMsg( $this->legendMsg )
212            ->suppressDefaultSubmit()
213            ->setSubmitCallback( static function () {
214                // no-op
215            } )
216            ->show();
217    }
218
219    /**
220     * @see SpecialWikibaseQueryPage::getResult
221     *
222     * @param int $offset
223     * @param int $limit
224     * @return array empty array
225     */
226    protected function getResult( $offset = 0, $limit = 0 ) {
227        $title = Title::makeTitle( NS_SPECIAL, 'Search' );
228        $ns = $this->entityNamespaceLookup->getEntityNamespace( $this->requestedEntityType );
229        $url = $title->getFullUrlForRedirect( "sort=relevance&search=-has{$this->termType}:{$this->requestedLanguageCode}&ns$ns=1" );
230        $this->getOutput()->redirect( $url );
231
232        return [];
233    }
234
235    /**
236     * @inheritDoc
237     */
238    protected function getTitleForNavigation() {
239        return $this->getPageTitle( $this->requestedLanguageCode . '/' . $this->requestedEntityType );
240    }
241
242}