MediaWiki master
SpecialPageLanguage.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
15use MediaWiki\Languages\LanguageNameUtils;
29
41 private $goToUrl;
42
43 private IContentHandlerFactory $contentHandlerFactory;
44 private LanguageNameUtils $languageNameUtils;
45 private IConnectionProvider $dbProvider;
46 private SearchEngineFactory $searchEngineFactory;
47
48 public function __construct(
49 IContentHandlerFactory $contentHandlerFactory,
50 LanguageNameUtils $languageNameUtils,
51 IConnectionProvider $dbProvider,
52 SearchEngineFactory $searchEngineFactory
53 ) {
54 parent::__construct( 'PageLanguage', 'pagelang' );
55 $this->contentHandlerFactory = $contentHandlerFactory;
56 $this->languageNameUtils = $languageNameUtils;
57 $this->dbProvider = $dbProvider;
58 $this->searchEngineFactory = $searchEngineFactory;
59 }
60
62 public function doesWrites() {
63 return true;
64 }
65
67 protected function preHtml() {
68 $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
69 return parent::preHtml();
70 }
71
73 protected function getFormFields() {
74 // Get default from the subpage of Special page
75 $defaultName = $this->par;
76 $title = $defaultName ? Title::newFromText( $defaultName ) : null;
77 if ( $title ) {
78 $defaultPageLanguage = $this->contentHandlerFactory->getContentHandler( $title->getContentModel() )
79 ->getPageLanguage( $title );
80
81 $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
82 } else {
83 $hasCustomLanguageSet = false;
84 }
85
86 $page = [];
87 $page['pagename'] = [
88 'type' => 'title',
89 'label-message' => 'pagelang-name',
90 'default' => $title ? $title->getPrefixedText() : $defaultName,
91 'autofocus' => $defaultName === null,
92 'exists' => true,
93 ];
94
95 // Options for whether to use the default language or select language
96 $selectoptions = [
97 (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
98 (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
99 ];
100 $page['selectoptions'] = [
101 'id' => 'mw-pl-options',
102 'type' => 'radio',
103 'options' => $selectoptions,
104 'default' => $hasCustomLanguageSet ? 2 : 1
105 ];
106
107 // Building a language selector
108 $userLang = $this->getLanguage()->getCode();
109 $languages = $this->languageNameUtils->getLanguageNames( $userLang, LanguageNameUtils::SUPPORTED );
110 $options = [];
111 foreach ( $languages as $code => $name ) {
112 $options["$code - $name"] = $code;
113 }
114
115 $page['language'] = [
116 'id' => 'mw-pl-languageselector',
117 'cssclass' => 'mw-languageselector',
118 'type' => 'select',
119 'options' => $options,
120 'label-message' => 'pagelang-language',
121 'default' => $title ?
122 $title->getPageLanguage()->getCode() :
124 ];
125
126 // Allow user to enter a comment explaining the change
127 $page['reason'] = [
128 'type' => 'text',
129 'label-message' => 'pagelang-reason'
130 ];
131
132 return $page;
133 }
134
136 protected function postHtml() {
137 if ( $this->par ) {
138 return $this->showLogFragment( $this->par );
139 }
140 return '';
141 }
142
144 protected function getDisplayFormat() {
145 return 'ooui';
146 }
147
148 public function alterForm( HTMLForm $form ) {
149 $this->getHookRunner()->onLanguageSelector( $this->getOutput(), 'mw-languageselector' );
150 $form->setSubmitTextMsg( 'pagelang-submit' );
151 }
152
157 public function onSubmit( array $data ) {
158 $pageName = $data['pagename'];
159
160 // Check if user wants to use default language
161 if ( $data['selectoptions'] == 1 ) {
162 $newLanguage = 'default';
163 } else {
164 $newLanguage = $data['language'];
165 }
166
167 try {
168 $title = Title::newFromTextThrow( $pageName );
169 } catch ( MalformedTitleException $ex ) {
170 return Status::newFatal( $ex->getMessageObject() );
171 }
172
173 // Check permissions and make sure the user has permission to edit the page
174 $status = PermissionStatus::newEmpty();
175 if ( !$this->getAuthority()->authorizeWrite( 'edit', $title, $status ) ) {
176 $wikitext = $this->getOutput()->formatPermissionStatus( $status );
177 // Hack to get our wikitext parsed
178 return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
179 }
180
181 // Url to redirect to after the operation
182 $this->goToUrl = $title->getFullUrlForRedirect(
183 $title->isRedirect() ? [ 'redirect' => 'no' ] : []
184 );
185
187 $this->getContext(),
188 $title,
189 $newLanguage,
190 $data['reason'] ?? '',
191 [],
192 $this->dbProvider->getPrimaryDatabase()
193 );
194 }
195
207 public static function changePageLanguage( IContextSource $context, Title $title,
208 $newLanguage, $reason = "", array $tags = [], ?IDatabase $dbw = null ) {
209 // Get the default language for the wiki
210 $defLang = $context->getConfig()->get( MainConfigNames::LanguageCode );
211
212 $pageId = $title->getArticleID();
213
214 // Check if article exists
215 if ( !$pageId ) {
216 return Status::newFatal(
217 'pagelang-nonexistent-page',
219 );
220 }
221
222 // Load the page language from DB
223 $dbw ??= MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
224 $oldLanguage = $dbw->newSelectQueryBuilder()
225 ->select( 'page_lang' )
226 ->from( 'page' )
227 ->where( [ 'page_id' => $pageId ] )
228 ->caller( __METHOD__ )->fetchField();
229
230 // Check if user wants to use the default language
231 if ( $newLanguage === 'default' ) {
232 $newLanguage = null;
233 }
234
235 // No change in language
236 if ( $newLanguage === $oldLanguage ) {
237 // Check if old language does not exist
238 if ( !$oldLanguage ) {
239 return Status::newFatal( ApiMessage::create(
240 [
241 'pagelang-unchanged-language-default',
243 ],
244 'pagelang-unchanged-language'
245 ) );
246 }
247 return Status::newFatal(
248 'pagelang-unchanged-language',
250 $oldLanguage
251 );
252 }
253
254 // Hardcoded [def] if the language is set to null
255 $logOld = $oldLanguage ?: $defLang . '[def]';
256 $logNew = $newLanguage ?: $defLang . '[def]';
257
258 // Writing new page language to database
259 $dbw->newUpdateQueryBuilder()
260 ->update( 'page' )
261 ->set( [ 'page_lang' => $newLanguage ] )
262 ->where( [
263 'page_id' => $pageId,
264 'page_lang' => $oldLanguage,
265 ] )
266 ->caller( __METHOD__ )->execute();
267
268 if ( !$dbw->affectedRows() ) {
269 return Status::newFatal( 'pagelang-db-failed' );
270 }
271
272 // Logging change of language
273 $logParams = [
274 '4::oldlanguage' => $logOld,
275 '5::newlanguage' => $logNew
276 ];
277 $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
278 $entry->setPerformer( $context->getUser() );
279 $entry->setTarget( $title );
280 $entry->setParameters( $logParams );
281 $entry->setComment( is_string( $reason ) ? $reason : "" );
282 $entry->addTags( $tags );
283
284 $logid = $entry->insert();
285 $entry->publish( $logid );
286
287 // Force re-render so that language-based content (parser functions etc.) gets updated
288 $title->invalidateCache();
289
290 return Status::newGood( (object)[
291 'oldLanguage' => $logOld,
292 'newLanguage' => $logNew,
293 'logId' => $logid,
294 ] );
295 }
296
297 public function onSuccess() {
298 // Success causes a redirect
299 $this->getOutput()->redirect( $this->goToUrl );
300 }
301
302 private function showLogFragment( string $title ): string {
303 $moveLogPage = new LogPage( 'pagelang' );
304 $out1 = Html::element( 'h2', [], $moveLogPage->getName()->text() );
305 $out2 = '';
306 LogEventsList::showLogExtract( $out2, 'pagelang', $title );
307 return $out1 . $out2;
308 }
309
318 public function prefixSearchSubpages( $search, $limit, $offset ) {
319 return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
320 }
321
323 protected function getGroupName() {
324 return 'pagetools';
325 }
326}
327
332class_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.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:195
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
Variant of the Message class.
Class to simplify the use of log pages.
Definition LogPage.php:35
Class for creating new log entries and inserting them into the database.
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 subpage of the special page.
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.See HTMLForm documentation for available values.1....
__construct(IContentHandlerFactory $contentHandlerFactory, LanguageNameUtils $languageNameUtils, IConnectionProvider $dbProvider, SearchEngineFactory $searchEngineFactory)
static changePageLanguage(IContextSource $context, Title $title, $newLanguage, $reason="", array $tags=[], ?IDatabase $dbw=null)
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...
doesWrites()
Indicates whether POST requests to this special page require write access to the wiki....
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
preHtml()
Add pre-HTML to the form.string HTML which will be sent to $form->addPreHtml() 1.38
postHtml()
Add post-HTML to the form.string HTML which will be sent to $form->addPostHtml() 1....
getFormFields()
Get an HTMLForm descriptor array.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:44
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Represents a title within MediaWiki.
Definition Title.php:70
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition Title.php:2559
invalidateCache( $purgeTime=null)
Updates page_touched for this page; called from LinksUpdate.php.
Definition Title.php:3299
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1858
Factory class for SearchEngine.
Interface for objects which can provide a MediaWiki context on request.
getConfig()
Get the site configuration.
Provide primary and replica IDatabase connections.
Interface to a relational database.
Definition IDatabase.php:31
element(SerializerNode $parent, SerializerNode $node, $contents)