Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
70.43% |
81 / 115 |
|
53.85% |
7 / 13 |
CRAP | |
0.00% |
0 / 1 |
SpecialMIMESearch | |
71.05% |
81 / 114 |
|
53.85% |
7 / 13 |
31.70 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
isExpensive | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isSyndicated | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isCacheable | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
linkParameters | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getQueryInfo | |
100.00% |
35 / 35 |
|
100.00% |
1 / 1 |
2 | |||
getOrderFields | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPageHeader | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
1 | |||
getSuggestionsForTypes | |
68.42% |
13 / 19 |
|
0.00% |
0 / 1 |
3.28 | |||
execute | |
66.67% |
8 / 12 |
|
0.00% |
0 / 1 |
7.33 | |||
formatResult | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
2 | |||
preprocessResults | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Specials; |
22 | |
23 | use File; |
24 | use HtmlArmor; |
25 | use LocalFile; |
26 | use MediaWiki\Cache\LinkBatchFactory; |
27 | use MediaWiki\HTMLForm\HTMLForm; |
28 | use MediaWiki\Language\ILanguageConverter; |
29 | use MediaWiki\Languages\LanguageConverterFactory; |
30 | use MediaWiki\Linker\Linker; |
31 | use MediaWiki\MediaWikiServices; |
32 | use MediaWiki\SpecialPage\QueryPage; |
33 | use MediaWiki\Title\Title; |
34 | use Skin; |
35 | use stdClass; |
36 | use Wikimedia\Rdbms\IConnectionProvider; |
37 | |
38 | /** |
39 | * Search the database for files of the requested MIME type, comparing this with the |
40 | * 'img_major_mime' and 'img_minor_mime' fields in the image table. |
41 | * |
42 | * @ingroup SpecialPage |
43 | * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> |
44 | */ |
45 | class SpecialMIMESearch extends QueryPage { |
46 | /** @var string */ |
47 | protected $major; |
48 | /** @var string */ |
49 | protected $minor; |
50 | /** @var string */ |
51 | protected $mime; |
52 | |
53 | private ILanguageConverter $languageConverter; |
54 | |
55 | /** |
56 | * @param IConnectionProvider $dbProvider |
57 | * @param LinkBatchFactory $linkBatchFactory |
58 | * @param LanguageConverterFactory $languageConverterFactory |
59 | */ |
60 | public function __construct( |
61 | IConnectionProvider $dbProvider, |
62 | LinkBatchFactory $linkBatchFactory, |
63 | LanguageConverterFactory $languageConverterFactory |
64 | ) { |
65 | parent::__construct( 'MIMEsearch' ); |
66 | $this->setDatabaseProvider( $dbProvider ); |
67 | $this->setLinkBatchFactory( $linkBatchFactory ); |
68 | $this->languageConverter = $languageConverterFactory->getLanguageConverter( $this->getContentLanguage() ); |
69 | } |
70 | |
71 | public function isExpensive() { |
72 | return false; |
73 | } |
74 | |
75 | public function isSyndicated() { |
76 | return false; |
77 | } |
78 | |
79 | public function isCacheable() { |
80 | return false; |
81 | } |
82 | |
83 | protected function linkParameters() { |
84 | return [ 'mime' => "{$this->major}/{$this->minor}" ]; |
85 | } |
86 | |
87 | public function getQueryInfo() { |
88 | $minorType = []; |
89 | if ( $this->minor !== '*' ) { |
90 | // Allow wildcard searching |
91 | $minorType['img_minor_mime'] = $this->minor; |
92 | } |
93 | $imgQuery = LocalFile::getQueryInfo(); |
94 | $qi = [ |
95 | 'tables' => $imgQuery['tables'], |
96 | 'fields' => [ |
97 | 'namespace' => NS_FILE, |
98 | 'title' => 'img_name', |
99 | // Still have a value field just in case, |
100 | // but it isn't actually used for sorting. |
101 | 'value' => 'img_name', |
102 | 'img_size', |
103 | 'img_width', |
104 | 'img_height', |
105 | 'img_user_text' => $imgQuery['fields']['img_user_text'], |
106 | 'img_timestamp' |
107 | ], |
108 | 'conds' => [ |
109 | 'img_major_mime' => $this->major, |
110 | // This is in order to trigger using |
111 | // the img_media_mime index in "range" mode. |
112 | // @todo how is order defined? use MimeAnalyzer::getMediaTypes? |
113 | 'img_media_type' => [ |
114 | MEDIATYPE_BITMAP, |
115 | MEDIATYPE_DRAWING, |
116 | MEDIATYPE_AUDIO, |
117 | MEDIATYPE_VIDEO, |
118 | MEDIATYPE_MULTIMEDIA, |
119 | MEDIATYPE_UNKNOWN, |
120 | MEDIATYPE_OFFICE, |
121 | MEDIATYPE_TEXT, |
122 | MEDIATYPE_EXECUTABLE, |
123 | MEDIATYPE_ARCHIVE, |
124 | MEDIATYPE_3D, |
125 | ], |
126 | ] + $minorType, |
127 | 'join_conds' => $imgQuery['joins'], |
128 | ]; |
129 | |
130 | return $qi; |
131 | } |
132 | |
133 | /** |
134 | * The index is on (img_media_type, img_major_mime, img_minor_mime) |
135 | * which unfortunately doesn't have img_name at the end for sorting. |
136 | * So tell db to sort it however it wishes (Its not super important |
137 | * that this report gives results in a logical order). As an additional |
138 | * note, mysql seems to by default order things by img_name ASC, which |
139 | * is what we ideally want, so everything works out fine anyhow. |
140 | * @return array |
141 | */ |
142 | protected function getOrderFields() { |
143 | return []; |
144 | } |
145 | |
146 | /** |
147 | * Generate and output the form |
148 | * @return string |
149 | */ |
150 | protected function getPageHeader() { |
151 | $formDescriptor = [ |
152 | 'mime' => [ |
153 | 'type' => 'combobox', |
154 | 'options' => $this->getSuggestionsForTypes(), |
155 | 'name' => 'mime', |
156 | 'label-message' => 'mimetype', |
157 | 'required' => true, |
158 | 'default' => $this->mime, |
159 | ], |
160 | ]; |
161 | |
162 | HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ) |
163 | ->setSubmitTextMsg( 'ilsubmit' ) |
164 | ->setTitle( $this->getPageTitle() ) |
165 | ->setMethod( 'get' ) |
166 | ->prepareForm() |
167 | ->displayForm( false ); |
168 | return ''; |
169 | } |
170 | |
171 | protected function getSuggestionsForTypes() { |
172 | $queryBuilder = $this->getDatabaseProvider()->getReplicaDatabase()->newSelectQueryBuilder(); |
173 | $queryBuilder |
174 | // We ignore img_media_type, but using it in the query is needed for MySQL to choose a |
175 | // sensible execution plan |
176 | ->select( [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ) |
177 | ->from( 'image' ) |
178 | ->groupBy( [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ); |
179 | $result = $queryBuilder->caller( __METHOD__ )->fetchResultSet(); |
180 | |
181 | $lastMajor = null; |
182 | $suggestions = []; |
183 | foreach ( $result as $row ) { |
184 | $major = $row->img_major_mime; |
185 | $minor = $row->img_minor_mime; |
186 | $suggestions[ "$major/$minor" ] = "$major/$minor"; |
187 | if ( $lastMajor === $major ) { |
188 | // If there are at least two with the same major mime type, also include the wildcard |
189 | $suggestions[ "$major/*" ] = "$major/*"; |
190 | } |
191 | $lastMajor = $major; |
192 | } |
193 | ksort( $suggestions ); |
194 | return $suggestions; |
195 | } |
196 | |
197 | public function execute( $par ) { |
198 | $this->addHelpLink( 'Help:Managing_files' ); |
199 | $this->mime = $par ?: $this->getRequest()->getText( 'mime' ); |
200 | $this->mime = trim( $this->mime ); |
201 | [ $this->major, $this->minor ] = File::splitMime( $this->mime ); |
202 | $mimeAnalyzer = MediaWikiServices::getInstance()->getMimeAnalyzer(); |
203 | |
204 | if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' || |
205 | !$mimeAnalyzer->isValidMajorMimeType( $this->major ) |
206 | ) { |
207 | $this->setHeaders(); |
208 | $this->outputHeader(); |
209 | $this->getPageHeader(); |
210 | return; |
211 | } |
212 | |
213 | parent::execute( $par ); |
214 | } |
215 | |
216 | /** |
217 | * @param Skin $skin |
218 | * @param stdClass $result Result row |
219 | * @return string |
220 | */ |
221 | public function formatResult( $skin, $result ) { |
222 | $linkRenderer = $this->getLinkRenderer(); |
223 | $nt = Title::makeTitle( $result->namespace, $result->title ); |
224 | |
225 | $text = $this->languageConverter->convertHtml( $nt->getText() ); |
226 | $plink = $linkRenderer->makeLink( |
227 | Title::newFromText( $nt->getPrefixedText() ), |
228 | new HtmlArmor( $text ) |
229 | ); |
230 | |
231 | $download = Linker::makeMediaLinkObj( $nt, $this->msg( 'download' )->escaped() ); |
232 | $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped(); |
233 | $lang = $this->getLanguage(); |
234 | $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) ); |
235 | $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width, |
236 | $result->img_height )->escaped(); |
237 | $user = $linkRenderer->makeLink( |
238 | Title::makeTitle( NS_USER, $result->img_user_text ), |
239 | $result->img_user_text |
240 | ); |
241 | |
242 | $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() ); |
243 | $time = htmlspecialchars( $time ); |
244 | |
245 | return "$download $plink . . $dimensions . . $bytes . . $user . . $time"; |
246 | } |
247 | |
248 | public function preprocessResults( $db, $res ) { |
249 | $this->executeLBFromResultWrapper( $res ); |
250 | } |
251 | |
252 | protected function getGroupName() { |
253 | return 'media'; |
254 | } |
255 | } |
256 | |
257 | /** |
258 | * Retain the old class name for backwards compatibility. |
259 | * @deprecated since 1.41 |
260 | */ |
261 | class_alias( SpecialMIMESearch::class, 'SpecialMIMESearch' ); |