MediaWiki master
SpecialPageLanguage.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
29
41 private $goToUrl;
42
43 public function __construct(
44 private readonly IContentHandlerFactory $contentHandlerFactory,
45 private readonly LanguageNameUtils $languageNameUtils,
46 private readonly IConnectionProvider $dbProvider,
47 private readonly SearchEngineFactory $searchEngineFactory,
48 ) {
49 parent::__construct( 'PageLanguage', 'pagelang' );
50 }
51
53 public function doesWrites() {
54 return true;
55 }
56
58 protected function preHtml() {
59 $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
60 return parent::preHtml();
61 }
62
64 protected function getFormFields() {
65 // Get default from the subpage of Special page
66 $defaultName = $this->par;
67 $title = $defaultName ? Title::newFromText( $defaultName ) : null;
68 if ( $title ) {
69 $defaultPageLanguage = $this->contentHandlerFactory->getContentHandler( $title->getContentModel() )
70 ->getPageLanguage( $title );
71
72 $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
73 } else {
74 $hasCustomLanguageSet = false;
75 }
76
77 $page = [];
78 $page['pagename'] = [
79 'type' => 'title',
80 'label-message' => 'pagelang-name',
81 'default' => $title ? $title->getPrefixedText() : $defaultName,
82 'autofocus' => $defaultName === null,
83 'exists' => true,
84 ];
85
86 // Options for whether to use the default language or select language
87 $selectoptions = [
88 (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
89 (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
90 ];
91 $page['selectoptions'] = [
92 'id' => 'mw-pl-options',
93 'type' => 'radio',
94 'options' => $selectoptions,
95 'default' => $hasCustomLanguageSet ? 2 : 1
96 ];
97
98 // Building a language selector
99 $page['language'] = [
100 'id' => 'mw-pl-languageselector',
101 'cssclass' => 'mw-languageselector',
102 'type' => 'language',
103 'useCodex' => true,
104 'label-message' => 'pagelang-language',
105 'value' => $title ?
106 $title->getPageLanguage()->getCode() :
108 ];
109
110 // Allow user to enter a comment explaining the change
111 $page['reason'] = [
112 'type' => 'text',
113 'label-message' => 'pagelang-reason'
114 ];
115
116 return $page;
117 }
118
120 protected function postHtml() {
121 if ( $this->par ) {
122 return $this->showLogFragment( $this->par );
123 }
124 return '';
125 }
126
128 protected function getDisplayFormat() {
129 return 'ooui';
130 }
131
132 public function alterForm( HTMLForm $form ) {
133 $this->getHookRunner()->onLanguageSelector( $this->getOutput(), 'mw-languageselector' );
134 $form->setId( 'mw-pagelanguage-form' )
135 ->setSubmitTextMsg( 'pagelang-submit' );
136 }
137
142 public function onSubmit( array $data ) {
143 $pageName = $data['pagename'];
144
145 // Check if user wants to use default language
146 if ( $data['selectoptions'] == 1 ) {
147 $newLanguage = 'default';
148 } else {
149 $newLanguage = $data['language'];
150 }
151
152 try {
153 $title = Title::newFromTextThrow( $pageName );
154 } catch ( MalformedTitleException $ex ) {
155 return Status::newFatal( $ex->getMessageObject() );
156 }
157
158 // Check permissions and make sure the user has permission to edit the page
159 $status = PermissionStatus::newEmpty();
160 if ( !$this->getAuthority()->authorizeWrite( 'edit', $title, $status ) ) {
161 $wikitext = $this->getOutput()->formatPermissionStatus( $status );
162 // Hack to get our wikitext parsed
163 return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
164 }
165
166 // Url to redirect to after the operation
167 $this->goToUrl = $title->getFullUrlForRedirect(
168 $title->isRedirect() ? [ 'redirect' => 'no' ] : []
169 );
170
172 $this->getContext(),
173 $title,
174 $newLanguage,
175 $data['reason'] ?? '',
176 [],
177 $this->dbProvider->getPrimaryDatabase()
178 );
179 }
180
192 public static function changePageLanguage( IContextSource $context, Title $title,
193 $newLanguage, $reason = "", array $tags = [], ?IDatabase $dbw = null ) {
194 // Get the default language for the wiki
195 $defLang = $context->getConfig()->get( MainConfigNames::LanguageCode );
196
197 $pageId = $title->getArticleID();
198
199 // Check if article exists
200 if ( !$pageId ) {
201 return Status::newFatal(
202 'pagelang-nonexistent-page',
204 );
205 }
206
207 // Load the page language from DB
208 $dbw ??= MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
209 $oldLanguage = $dbw->newSelectQueryBuilder()
210 ->select( 'page_lang' )
211 ->from( 'page' )
212 ->where( [ 'page_id' => $pageId ] )
213 ->caller( __METHOD__ )->fetchField();
214
215 // Check if user wants to use the default language
216 if ( $newLanguage === 'default' ) {
217 $newLanguage = null;
218 }
219
220 // No change in language
221 if ( $newLanguage === $oldLanguage ) {
222 // Check if old language does not exist
223 if ( !$oldLanguage ) {
224 return Status::newFatal( ApiMessage::create(
225 [
226 'pagelang-unchanged-language-default',
228 ],
229 'pagelang-unchanged-language'
230 ) );
231 }
232 return Status::newFatal(
233 'pagelang-unchanged-language',
235 $oldLanguage
236 );
237 }
238
239 // Hardcoded [def] if the language is set to null
240 $logOld = $oldLanguage ?: $defLang . '[def]';
241 $logNew = $newLanguage ?: $defLang . '[def]';
242
243 // Writing new page language to database
244 $pageUpdate = $dbw->newUpdateQueryBuilder()
245 ->update( 'page' )
246 ->set( [ 'page_lang' => $newLanguage ] )
247 ->where( [
248 'page_id' => $pageId,
249 'page_lang' => $oldLanguage,
250 ] )
251 ->caller( __METHOD__ );
252 $pageUpdate->execute();
253 MediaWikiServices::getInstance()->getLinkWriteDuplicator()->duplicate( $pageUpdate );
254
255 if ( !$dbw->affectedRows() ) {
256 return Status::newFatal( 'pagelang-db-failed' );
257 }
258
259 // Logging change of language
260 $logParams = [
261 '4::oldlanguage' => $logOld,
262 '5::newlanguage' => $logNew
263 ];
264 $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
265 $entry->setPerformer( $context->getUser() );
266 $entry->setTarget( $title );
267 $entry->setParameters( $logParams );
268 $entry->setComment( is_string( $reason ) ? $reason : "" );
269 $entry->addTags( $tags );
270
271 $logid = $entry->insert();
272 $entry->publish( $logid );
273
274 // Force re-render so that language-based content (parser functions etc.) gets updated
275 $title->invalidateCache();
276
277 return Status::newGood( (object)[
278 'oldLanguage' => $logOld,
279 'newLanguage' => $logNew,
280 'logId' => $logid,
281 ] );
282 }
283
284 public function onSuccess() {
285 // Success causes a redirect
286 $this->getOutput()->redirect( $this->goToUrl );
287 }
288
289 private function showLogFragment( string $title ): string {
290 $moveLogPage = new LogPage( 'pagelang' );
291 $out1 = Html::element( 'h2', [], $moveLogPage->getName()->text() );
292 $out2 = '';
293 LogEventsList::showLogExtract( $out2, 'pagelang', $title );
294 return $out1 . $out2;
295 }
296
305 public function prefixSearchSubpages( $search, $limit, $offset ) {
306 return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
307 }
308
310 protected function getGroupName() {
311 return 'pagetools';
312 }
313}
314
319class_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:207
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
A service that provides utilities to do with language names and codes.
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.
Factory class for SearchEngine.
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.
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(private readonly IContentHandlerFactory $contentHandlerFactory, private readonly LanguageNameUtils $languageNameUtils, private readonly IConnectionProvider $dbProvider, private readonly 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:69
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition Title.php:2558
invalidateCache( $purgeTime=null)
Updates page_touched for this page; called from LinksUpdate.php.
Definition Title.php:3298
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1857
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)