MediaWiki  master
SpecialPageLanguage.php
Go to the documentation of this file.
1 <?php
32 
42  private $goToUrl;
43 
45  private $contentHandlerFactory;
46 
48  private $languageNameUtils;
49 
51  private $loadBalancer;
52 
54  private $searchEngineFactory;
55 
62  public function __construct(
63  IContentHandlerFactory $contentHandlerFactory,
64  LanguageNameUtils $languageNameUtils,
65  ILoadBalancer $loadBalancer,
66  SearchEngineFactory $searchEngineFactory
67  ) {
68  parent::__construct( 'PageLanguage', 'pagelang' );
69  $this->contentHandlerFactory = $contentHandlerFactory;
70  $this->languageNameUtils = $languageNameUtils;
71  $this->loadBalancer = $loadBalancer;
72  $this->searchEngineFactory = $searchEngineFactory;
73  }
74 
75  public function doesWrites() {
76  return true;
77  }
78 
79  protected function preHtml() {
80  $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
81  return parent::preHtml();
82  }
83 
84  protected function getFormFields() {
85  // Get default from the subpage of Special page
86  $defaultName = $this->par;
87  $title = $defaultName ? Title::newFromText( $defaultName ) : null;
88  if ( $title ) {
89  $defaultPageLanguage = $this->contentHandlerFactory->getContentHandler( $title->getContentModel() )
90  ->getPageLanguage( $title );
91 
92  $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
93  } else {
94  $hasCustomLanguageSet = false;
95  }
96 
97  $page = [];
98  $page['pagename'] = [
99  'type' => 'title',
100  'label-message' => 'pagelang-name',
101  'default' => $title ? $title->getPrefixedText() : $defaultName,
102  'autofocus' => $defaultName === null,
103  'exists' => true,
104  ];
105 
106  // Options for whether to use the default language or select language
107  $selectoptions = [
108  (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
109  (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
110  ];
111  $page['selectoptions'] = [
112  'id' => 'mw-pl-options',
113  'type' => 'radio',
114  'options' => $selectoptions,
115  'default' => $hasCustomLanguageSet ? 2 : 1
116  ];
117 
118  // Building a language selector
119  $userLang = $this->getLanguage()->getCode();
120  $languages = $this->languageNameUtils->getLanguageNames( $userLang, LanguageNameUtils::SUPPORTED );
121  $options = [];
122  foreach ( $languages as $code => $name ) {
123  $options["$code - $name"] = $code;
124  }
125 
126  $page['language'] = [
127  'id' => 'mw-pl-languageselector',
128  'cssclass' => 'mw-languageselector',
129  'type' => 'select',
130  'options' => $options,
131  'label-message' => 'pagelang-language',
132  'default' => $title ?
133  $title->getPageLanguage()->getCode() :
134  $this->getConfig()->get( MainConfigNames::LanguageCode ),
135  ];
136 
137  // Allow user to enter a comment explaining the change
138  $page['reason'] = [
139  'type' => 'text',
140  'label-message' => 'pagelang-reason'
141  ];
142 
143  return $page;
144  }
145 
146  protected function postHtml() {
147  if ( $this->par ) {
148  return $this->showLogFragment( $this->par );
149  }
150  return '';
151  }
152 
153  protected function getDisplayFormat() {
154  return 'ooui';
155  }
156 
157  public function alterForm( HTMLForm $form ) {
158  $this->getHookRunner()->onLanguageSelector( $this->getOutput(), 'mw-languageselector' );
159  $form->setSubmitTextMsg( 'pagelang-submit' );
160  }
161 
166  public function onSubmit( array $data ) {
167  $pageName = $data['pagename'];
168 
169  // Check if user wants to use default language
170  if ( $data['selectoptions'] == 1 ) {
171  $newLanguage = 'default';
172  } else {
173  $newLanguage = $data['language'];
174  }
175 
176  try {
177  $title = Title::newFromTextThrow( $pageName );
178  } catch ( MalformedTitleException $ex ) {
179  return Status::newFatal( $ex->getMessageObject() );
180  }
181 
182  // Check permissions and make sure the user has permission to edit the page
183  $status = PermissionStatus::newEmpty();
184  if ( !$this->getAuthority()->authorizeWrite( 'edit', $title, $status ) ) {
185  $wikitext = $this->getOutput()->formatPermissionStatus( $status );
186  // Hack to get our wikitext parsed
187  return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
188  }
189 
190  // Url to redirect to after the operation
191  $this->goToUrl = $title->getFullUrlForRedirect(
192  $title->isRedirect() ? [ 'redirect' => 'no' ] : []
193  );
194 
196  $this->getContext(),
197  $title,
198  $newLanguage,
199  $data['reason'] ?? '',
200  [],
201  $this->loadBalancer->getConnectionRef( ILoadBalancer::DB_PRIMARY )
202  );
203  }
204 
216  public static function changePageLanguage( IContextSource $context, Title $title,
217  $newLanguage, $reason = "", array $tags = [], IDatabase $dbw = null ) {
218  // Get the default language for the wiki
219  $defLang = $context->getConfig()->get( MainConfigNames::LanguageCode );
220 
221  $pageId = $title->getArticleID();
222 
223  // Check if article exists
224  if ( !$pageId ) {
225  return Status::newFatal(
226  'pagelang-nonexistent-page',
227  wfEscapeWikiText( $title->getPrefixedText() )
228  );
229  }
230 
231  // Load the page language from DB
232  $dbw = $dbw ?? wfGetDB( DB_PRIMARY );
233  $oldLanguage = $dbw->selectField(
234  'page',
235  'page_lang',
236  [ 'page_id' => $pageId ],
237  __METHOD__
238  );
239 
240  // Check if user wants to use the default language
241  if ( $newLanguage === 'default' ) {
242  $newLanguage = null;
243  }
244 
245  // No change in language
246  if ( $newLanguage === $oldLanguage ) {
247  // Check if old language does not exist
248  if ( !$oldLanguage ) {
250  [
251  'pagelang-unchanged-language-default',
252  wfEscapeWikiText( $title->getPrefixedText() )
253  ],
254  'pagelang-unchanged-language'
255  ) );
256  }
257  return Status::newFatal(
258  'pagelang-unchanged-language',
259  wfEscapeWikiText( $title->getPrefixedText() ),
260  $oldLanguage
261  );
262  }
263 
264  // Hardcoded [def] if the language is set to null
265  $logOld = $oldLanguage ?: $defLang . '[def]';
266  $logNew = $newLanguage ?: $defLang . '[def]';
267 
268  // Writing new page language to database
269  $dbw->update(
270  'page',
271  [ 'page_lang' => $newLanguage ],
272  [
273  'page_id' => $pageId,
274  'page_lang' => $oldLanguage
275  ],
276  __METHOD__
277  );
278 
279  if ( !$dbw->affectedRows() ) {
280  return Status::newFatal( 'pagelang-db-failed' );
281  }
282 
283  // Logging change of language
284  $logParams = [
285  '4::oldlanguage' => $logOld,
286  '5::newlanguage' => $logNew
287  ];
288  $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
289  $entry->setPerformer( $context->getUser() );
290  $entry->setTarget( $title );
291  $entry->setParameters( $logParams );
292  $entry->setComment( is_string( $reason ) ? $reason : "" );
293  $entry->addTags( $tags );
294 
295  $logid = $entry->insert();
296  $entry->publish( $logid );
297 
298  // Force re-render so that language-based content (parser functions etc.) gets updated
299  $title->invalidateCache();
300 
301  return Status::newGood( (object)[
302  'oldLanguage' => $logOld,
303  'newLanguage' => $logNew,
304  'logId' => $logid,
305  ] );
306  }
307 
308  public function onSuccess() {
309  // Success causes a redirect
310  $this->getOutput()->redirect( $this->goToUrl );
311  }
312 
313  private function showLogFragment( $title ) {
314  $moveLogPage = new LogPage( 'pagelang' );
315  $out1 = Xml::element( 'h2', null, $moveLogPage->getName()->text() );
316  $out2 = '';
317  LogEventsList::showLogExtract( $out2, 'pagelang', $title );
318  return $out1 . $out2;
319  }
320 
329  public function prefixSearchSubpages( $search, $limit, $offset ) {
330  return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
331  }
332 
333  protected function getGroupName() {
334  return 'pagetools';
335  }
336 }
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:43
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:150
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1604
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition: LogPage.php:39
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.
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.
Variant of the Message class.
Definition: RawMessage.php:35
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.
__construct(IContentHandlerFactory $contentHandlerFactory, LanguageNameUtils $languageNameUtils, ILoadBalancer $loadBalancer, SearchEngineFactory $searchEngineFactory)
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.
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:70
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
Represents a title within MediaWiki.
Definition: Title.php:49
static newFromTextThrow( $text, $defaultNamespace=NS_MAIN)
Like Title::newFromText(), but throws MalformedTitleException when the title is invalid,...
Definition: Title.php:405
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:370
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:43
Interface for objects which can provide a MediaWiki context on request.
getConfig()
Get the site configuration.
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:39
Create and track the database connections and transactions for a given database cluster.
const DB_PRIMARY
Definition: defines.php:28