MediaWiki master
SpecialPageLanguage.php
Go to the documentation of this file.
1<?php
26namespace MediaWiki\Specials;
27
28use ApiMessage;
30use LogPage;
47use Xml;
48
58 private $goToUrl;
59
60 private IContentHandlerFactory $contentHandlerFactory;
61 private LanguageNameUtils $languageNameUtils;
62 private IConnectionProvider $dbProvider;
63 private SearchEngineFactory $searchEngineFactory;
64
71 public function __construct(
72 IContentHandlerFactory $contentHandlerFactory,
73 LanguageNameUtils $languageNameUtils,
74 IConnectionProvider $dbProvider,
75 SearchEngineFactory $searchEngineFactory
76 ) {
77 parent::__construct( 'PageLanguage', 'pagelang' );
78 $this->contentHandlerFactory = $contentHandlerFactory;
79 $this->languageNameUtils = $languageNameUtils;
80 $this->dbProvider = $dbProvider;
81 $this->searchEngineFactory = $searchEngineFactory;
82 }
83
84 public function doesWrites() {
85 return true;
86 }
87
88 protected function preHtml() {
89 $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
90 return parent::preHtml();
91 }
92
93 protected function getFormFields() {
94 // Get default from the subpage of Special page
95 $defaultName = $this->par;
96 $title = $defaultName ? Title::newFromText( $defaultName ) : null;
97 if ( $title ) {
98 $defaultPageLanguage = $this->contentHandlerFactory->getContentHandler( $title->getContentModel() )
99 ->getPageLanguage( $title );
100
101 $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
102 } else {
103 $hasCustomLanguageSet = false;
104 }
105
106 $page = [];
107 $page['pagename'] = [
108 'type' => 'title',
109 'label-message' => 'pagelang-name',
110 'default' => $title ? $title->getPrefixedText() : $defaultName,
111 'autofocus' => $defaultName === null,
112 'exists' => true,
113 ];
114
115 // Options for whether to use the default language or select language
116 $selectoptions = [
117 (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
118 (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
119 ];
120 $page['selectoptions'] = [
121 'id' => 'mw-pl-options',
122 'type' => 'radio',
123 'options' => $selectoptions,
124 'default' => $hasCustomLanguageSet ? 2 : 1
125 ];
126
127 // Building a language selector
128 $userLang = $this->getLanguage()->getCode();
129 $languages = $this->languageNameUtils->getLanguageNames( $userLang, LanguageNameUtils::SUPPORTED );
130 $options = [];
131 foreach ( $languages as $code => $name ) {
132 $options["$code - $name"] = $code;
133 }
134
135 $page['language'] = [
136 'id' => 'mw-pl-languageselector',
137 'cssclass' => 'mw-languageselector',
138 'type' => 'select',
139 'options' => $options,
140 'label-message' => 'pagelang-language',
141 'default' => $title ?
142 $title->getPageLanguage()->getCode() :
144 ];
145
146 // Allow user to enter a comment explaining the change
147 $page['reason'] = [
148 'type' => 'text',
149 'label-message' => 'pagelang-reason'
150 ];
151
152 return $page;
153 }
154
155 protected function postHtml() {
156 if ( $this->par ) {
157 return $this->showLogFragment( $this->par );
158 }
159 return '';
160 }
161
162 protected function getDisplayFormat() {
163 return 'ooui';
164 }
165
166 public function alterForm( HTMLForm $form ) {
167 $this->getHookRunner()->onLanguageSelector( $this->getOutput(), 'mw-languageselector' );
168 $form->setSubmitTextMsg( 'pagelang-submit' );
169 }
170
175 public function onSubmit( array $data ) {
176 $pageName = $data['pagename'];
177
178 // Check if user wants to use default language
179 if ( $data['selectoptions'] == 1 ) {
180 $newLanguage = 'default';
181 } else {
182 $newLanguage = $data['language'];
183 }
184
185 try {
186 $title = Title::newFromTextThrow( $pageName );
187 } catch ( MalformedTitleException $ex ) {
188 return Status::newFatal( $ex->getMessageObject() );
189 }
190
191 // Check permissions and make sure the user has permission to edit the page
192 $status = PermissionStatus::newEmpty();
193 if ( !$this->getAuthority()->authorizeWrite( 'edit', $title, $status ) ) {
194 $wikitext = $this->getOutput()->formatPermissionStatus( $status );
195 // Hack to get our wikitext parsed
196 return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
197 }
198
199 // Url to redirect to after the operation
200 $this->goToUrl = $title->getFullUrlForRedirect(
201 $title->isRedirect() ? [ 'redirect' => 'no' ] : []
202 );
203
205 $this->getContext(),
206 $title,
207 $newLanguage,
208 $data['reason'] ?? '',
209 [],
210 $this->dbProvider->getPrimaryDatabase()
211 );
212 }
213
225 public static function changePageLanguage( IContextSource $context, Title $title,
226 $newLanguage, $reason = "", array $tags = [], IDatabase $dbw = null ) {
227 // Get the default language for the wiki
228 $defLang = $context->getConfig()->get( MainConfigNames::LanguageCode );
229
230 $pageId = $title->getArticleID();
231
232 // Check if article exists
233 if ( !$pageId ) {
234 return Status::newFatal(
235 'pagelang-nonexistent-page',
237 );
238 }
239
240 // Load the page language from DB
241 $dbw ??= MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
242 $oldLanguage = $dbw->newSelectQueryBuilder()
243 ->select( 'page_lang' )
244 ->from( 'page' )
245 ->where( [ 'page_id' => $pageId ] )
246 ->caller( __METHOD__ )->fetchField();
247
248 // Check if user wants to use the default language
249 if ( $newLanguage === 'default' ) {
250 $newLanguage = null;
251 }
252
253 // No change in language
254 if ( $newLanguage === $oldLanguage ) {
255 // Check if old language does not exist
256 if ( !$oldLanguage ) {
257 return Status::newFatal( ApiMessage::create(
258 [
259 'pagelang-unchanged-language-default',
261 ],
262 'pagelang-unchanged-language'
263 ) );
264 }
265 return Status::newFatal(
266 'pagelang-unchanged-language',
268 $oldLanguage
269 );
270 }
271
272 // Hardcoded [def] if the language is set to null
273 $logOld = $oldLanguage ?: $defLang . '[def]';
274 $logNew = $newLanguage ?: $defLang . '[def]';
275
276 // Writing new page language to database
277 $dbw->newUpdateQueryBuilder()
278 ->update( 'page' )
279 ->set( [ 'page_lang' => $newLanguage ] )
280 ->where( [
281 'page_id' => $pageId,
282 'page_lang' => $oldLanguage,
283 ] )
284 ->caller( __METHOD__ )->execute();
285
286 if ( !$dbw->affectedRows() ) {
287 return Status::newFatal( 'pagelang-db-failed' );
288 }
289
290 // Logging change of language
291 $logParams = [
292 '4::oldlanguage' => $logOld,
293 '5::newlanguage' => $logNew
294 ];
295 $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
296 $entry->setPerformer( $context->getUser() );
297 $entry->setTarget( $title );
298 $entry->setParameters( $logParams );
299 $entry->setComment( is_string( $reason ) ? $reason : "" );
300 $entry->addTags( $tags );
301
302 $logid = $entry->insert();
303 $entry->publish( $logid );
304
305 // Force re-render so that language-based content (parser functions etc.) gets updated
306 $title->invalidateCache();
307
308 return Status::newGood( (object)[
309 'oldLanguage' => $logOld,
310 'newLanguage' => $logNew,
311 'logId' => $logid,
312 ] );
313 }
314
315 public function onSuccess() {
316 // Success causes a redirect
317 $this->getOutput()->redirect( $this->goToUrl );
318 }
319
320 private function showLogFragment( $title ) {
321 $moveLogPage = new LogPage( 'pagelang' );
322 $out1 = Xml::element( 'h2', null, $moveLogPage->getName()->text() );
323 $out2 = '';
324 LogEventsList::showLogExtract( $out2, 'pagelang', $title );
325 return $out1 . $out2;
326 }
327
336 public function prefixSearchSubpages( $search, $limit, $offset ) {
337 return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
338 }
339
340 protected function getGroupName() {
341 return 'pagetools';
342 }
343}
344
349class_alias( SpecialPageLanguage::class, 'SpecialPageLanguage' );
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Extension of Message implementing IApiMessage.
Class to simplify the use of log pages.
Definition LogPage.php:44
Class for creating new log entries and inserting them into the database.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Variant of the Message class.
A service that provides utilities to do with language names and codes.
A class containing constants representing the names of configuration variables.
const LanguageCode
Name constant for the LanguageCode setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
A StatusValue for permission errors.
Special page which uses an HTMLForm to handle processing.
string null $par
The sub-page of the special page.
prefixSearchString( $search, $limit, $offset, SearchEngineFactory $searchEngineFactory=null)
Perform a regular substring search for prefixSearchSubpages.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
getLanguage()
Shortcut to get user's language.
Special page for changing the content language of a page.
getDisplayFormat()
Get display format for the form.
__construct(IContentHandlerFactory $contentHandlerFactory, LanguageNameUtils $languageNameUtils, IConnectionProvider $dbProvider, SearchEngineFactory $searchEngineFactory)
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
static changePageLanguage(IContextSource $context, Title $title, $newLanguage, $reason="", array $tags=[], IDatabase $dbw=null)
doesWrites()
Indicates whether this special page may perform database writes.
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
getFormFields()
Get an HTMLForm descriptor array.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Represents a title within MediaWiki.
Definition Title.php:78
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition Title.php:2590
invalidateCache( $purgeTime=null)
Updates page_touched for this page; called from LinksUpdate.php.
Definition Title.php:3380
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1861
Factory class for SearchEngine.
Module of static functions for generating XML.
Definition Xml.php:33
Interface for objects which can provide a MediaWiki context on request.
getConfig()
Get the site configuration.
Provide primary and replica IDatabase connections.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:36
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...