MediaWiki  master
SpecialPageLanguage.php
Go to the documentation of this file.
1 <?php
34 
44  private $goToUrl;
45 
47  private $contentHandlerFactory;
48 
50  private $languageNameUtils;
51 
53  private $dbProvider;
54 
56  private $searchEngineFactory;
57 
64  public function __construct(
65  IContentHandlerFactory $contentHandlerFactory,
66  LanguageNameUtils $languageNameUtils,
67  IConnectionProvider $dbProvider,
68  SearchEngineFactory $searchEngineFactory
69  ) {
70  parent::__construct( 'PageLanguage', 'pagelang' );
71  $this->contentHandlerFactory = $contentHandlerFactory;
72  $this->languageNameUtils = $languageNameUtils;
73  $this->dbProvider = $dbProvider;
74  $this->searchEngineFactory = $searchEngineFactory;
75  }
76 
77  public function doesWrites() {
78  return true;
79  }
80 
81  protected function preHtml() {
82  $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
83  return parent::preHtml();
84  }
85 
86  protected function getFormFields() {
87  // Get default from the subpage of Special page
88  $defaultName = $this->par;
89  $title = $defaultName ? Title::newFromText( $defaultName ) : null;
90  if ( $title ) {
91  $defaultPageLanguage = $this->contentHandlerFactory->getContentHandler( $title->getContentModel() )
92  ->getPageLanguage( $title );
93 
94  $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
95  } else {
96  $hasCustomLanguageSet = false;
97  }
98 
99  $page = [];
100  $page['pagename'] = [
101  'type' => 'title',
102  'label-message' => 'pagelang-name',
103  'default' => $title ? $title->getPrefixedText() : $defaultName,
104  'autofocus' => $defaultName === null,
105  'exists' => true,
106  ];
107 
108  // Options for whether to use the default language or select language
109  $selectoptions = [
110  (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
111  (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
112  ];
113  $page['selectoptions'] = [
114  'id' => 'mw-pl-options',
115  'type' => 'radio',
116  'options' => $selectoptions,
117  'default' => $hasCustomLanguageSet ? 2 : 1
118  ];
119 
120  // Building a language selector
121  $userLang = $this->getLanguage()->getCode();
122  $languages = $this->languageNameUtils->getLanguageNames( $userLang, LanguageNameUtils::SUPPORTED );
123  $options = [];
124  foreach ( $languages as $code => $name ) {
125  $options["$code - $name"] = $code;
126  }
127 
128  $page['language'] = [
129  'id' => 'mw-pl-languageselector',
130  'cssclass' => 'mw-languageselector',
131  'type' => 'select',
132  'options' => $options,
133  'label-message' => 'pagelang-language',
134  'default' => $title ?
135  $title->getPageLanguage()->getCode() :
136  $this->getConfig()->get( MainConfigNames::LanguageCode ),
137  ];
138 
139  // Allow user to enter a comment explaining the change
140  $page['reason'] = [
141  'type' => 'text',
142  'label-message' => 'pagelang-reason'
143  ];
144 
145  return $page;
146  }
147 
148  protected function postHtml() {
149  if ( $this->par ) {
150  return $this->showLogFragment( $this->par );
151  }
152  return '';
153  }
154 
155  protected function getDisplayFormat() {
156  return 'ooui';
157  }
158 
159  public function alterForm( HTMLForm $form ) {
160  $this->getHookRunner()->onLanguageSelector( $this->getOutput(), 'mw-languageselector' );
161  $form->setSubmitTextMsg( 'pagelang-submit' );
162  }
163 
168  public function onSubmit( array $data ) {
169  $pageName = $data['pagename'];
170 
171  // Check if user wants to use default language
172  if ( $data['selectoptions'] == 1 ) {
173  $newLanguage = 'default';
174  } else {
175  $newLanguage = $data['language'];
176  }
177 
178  try {
179  $title = Title::newFromTextThrow( $pageName );
180  } catch ( MalformedTitleException $ex ) {
181  return Status::newFatal( $ex->getMessageObject() );
182  }
183 
184  // Check permissions and make sure the user has permission to edit the page
185  $status = PermissionStatus::newEmpty();
186  if ( !$this->getAuthority()->authorizeWrite( 'edit', $title, $status ) ) {
187  $wikitext = $this->getOutput()->formatPermissionStatus( $status );
188  // Hack to get our wikitext parsed
189  return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
190  }
191 
192  // Url to redirect to after the operation
193  $this->goToUrl = $title->getFullUrlForRedirect(
194  $title->isRedirect() ? [ 'redirect' => 'no' ] : []
195  );
196 
198  $this->getContext(),
199  $title,
200  $newLanguage,
201  $data['reason'] ?? '',
202  [],
203  $this->dbProvider->getPrimaryDatabase()
204  );
205  }
206 
218  public static function changePageLanguage( IContextSource $context, Title $title,
219  $newLanguage, $reason = "", array $tags = [], IDatabase $dbw = null ) {
220  // Get the default language for the wiki
221  $defLang = $context->getConfig()->get( MainConfigNames::LanguageCode );
222 
223  $pageId = $title->getArticleID();
224 
225  // Check if article exists
226  if ( !$pageId ) {
227  return Status::newFatal(
228  'pagelang-nonexistent-page',
229  wfEscapeWikiText( $title->getPrefixedText() )
230  );
231  }
232 
233  // Load the page language from DB
234  $dbw ??= wfGetDB( DB_PRIMARY );
235  $oldLanguage = $dbw->selectField(
236  'page',
237  'page_lang',
238  [ 'page_id' => $pageId ],
239  __METHOD__
240  );
241 
242  // Check if user wants to use the default language
243  if ( $newLanguage === 'default' ) {
244  $newLanguage = null;
245  }
246 
247  // No change in language
248  if ( $newLanguage === $oldLanguage ) {
249  // Check if old language does not exist
250  if ( !$oldLanguage ) {
252  [
253  'pagelang-unchanged-language-default',
254  wfEscapeWikiText( $title->getPrefixedText() )
255  ],
256  'pagelang-unchanged-language'
257  ) );
258  }
259  return Status::newFatal(
260  'pagelang-unchanged-language',
261  wfEscapeWikiText( $title->getPrefixedText() ),
262  $oldLanguage
263  );
264  }
265 
266  // Hardcoded [def] if the language is set to null
267  $logOld = $oldLanguage ?: $defLang . '[def]';
268  $logNew = $newLanguage ?: $defLang . '[def]';
269 
270  // Writing new page language to database
271  $dbw->update(
272  'page',
273  [ 'page_lang' => $newLanguage ],
274  [
275  'page_id' => $pageId,
276  'page_lang' => $oldLanguage
277  ],
278  __METHOD__
279  );
280 
281  if ( !$dbw->affectedRows() ) {
282  return Status::newFatal( 'pagelang-db-failed' );
283  }
284 
285  // Logging change of language
286  $logParams = [
287  '4::oldlanguage' => $logOld,
288  '5::newlanguage' => $logNew
289  ];
290  $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
291  $entry->setPerformer( $context->getUser() );
292  $entry->setTarget( $title );
293  $entry->setParameters( $logParams );
294  $entry->setComment( is_string( $reason ) ? $reason : "" );
295  $entry->addTags( $tags );
296 
297  $logid = $entry->insert();
298  $entry->publish( $logid );
299 
300  // Force re-render so that language-based content (parser functions etc.) gets updated
301  $title->invalidateCache();
302 
303  return Status::newGood( (object)[
304  'oldLanguage' => $logOld,
305  'newLanguage' => $logNew,
306  'logId' => $logid,
307  ] );
308  }
309 
310  public function onSuccess() {
311  // Success causes a redirect
312  $this->getOutput()->redirect( $this->goToUrl );
313  }
314 
315  private function showLogFragment( $title ) {
316  $moveLogPage = new LogPage( 'pagelang' );
317  $out1 = Xml::element( 'h2', null, $moveLogPage->getName()->text() );
318  $out2 = '';
319  LogEventsList::showLogExtract( $out2, 'pagelang', $title );
320  return $out1 . $out2;
321  }
322 
331  public function prefixSearchSubpages( $search, $limit, $offset ) {
332  return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
333  }
334 
335  protected function getGroupName() {
336  return 'pagetools';
337  }
338 }
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:45
Special page which uses an HTMLForm to handle processing.
string null $par
The sub-page of the special page.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:155
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1637
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition: LogPage.php:41
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Class for creating new log entries and inserting them into the database.
Variant of the Message class.
Definition: RawMessage.php:40
A service that provides utilities to do with language names and codes.
A class containing constants representing the names of configuration variables.
A StatusValue for permission errors.
Represents a title within MediaWiki.
Definition: Title.php:82
Factory class for SearchEngine.
Special page for changing the content language of a page.
getFormFields()
Get an HTMLForm descriptor array.
postHtml()
Add post-HTML to the form.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
static changePageLanguage(IContextSource $context, Title $title, $newLanguage, $reason="", array $tags=[], IDatabase $dbw=null)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
preHtml()
Add pre-HTML to the form.
doesWrites()
Indicates whether this special page may perform database writes.
getDisplayFormat()
Get display format for the form.
__construct(IContentHandlerFactory $contentHandlerFactory, LanguageNameUtils $languageNameUtils, IConnectionProvider $dbProvider, SearchEngineFactory $searchEngineFactory)
getOutput()
Get the OutputPage being used for this instance.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getAuthority()
Shortcut to get the Authority executing this instance.
getConfig()
Shortcut to get main config object.
prefixSearchString( $search, $limit, $offset, SearchEngineFactory $searchEngineFactory=null)
Perform a regular substring search for prefixSearchSubpages.
getLanguage()
Shortcut to get user's language.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:73
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:85
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:44
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
const DB_PRIMARY
Definition: defines.php:28