MediaWiki  master
Action.php
Go to the documentation of this file.
1 <?php
23 
39 abstract class Action implements MessageLocalizer {
40 
46  protected $page;
47 
53  protected $context;
54 
60  protected $fields;
61 
69  final private static function getClass( $action, array $overrides ) {
70  global $wgActions;
71  $action = strtolower( $action );
72 
73  if ( !isset( $wgActions[$action] ) ) {
74  return null;
75  }
76 
77  if ( $wgActions[$action] === false ) {
78  return false;
79  } elseif ( $wgActions[$action] === true && isset( $overrides[$action] ) ) {
80  return $overrides[$action];
81  } elseif ( $wgActions[$action] === true ) {
82  return ucfirst( $action ) . 'Action';
83  } else {
84  return $wgActions[$action];
85  }
86  }
87 
97  final public static function factory( $action, Page $page, IContextSource $context = null ) {
98  $classOrCallable = self::getClass( $action, $page->getActionOverrides() );
99 
100  if ( is_string( $classOrCallable ) ) {
101  if ( !class_exists( $classOrCallable ) ) {
102  return false;
103  }
104  return new $classOrCallable( $page, $context );
105  }
106 
107  if ( is_callable( $classOrCallable ) ) {
108  return $classOrCallable( $page, $context );
109  }
110 
111  return $classOrCallable;
112  }
113 
123  final public static function getActionName( IContextSource $context ) {
124  global $wgActions;
125 
126  $request = $context->getRequest();
127  $actionName = $request->getVal( 'action', 'view' );
128 
129  // Check for disabled actions
130  if ( isset( $wgActions[$actionName] ) && $wgActions[$actionName] === false ) {
131  $actionName = 'nosuchaction';
132  }
133 
134  // Workaround for T22966: inability of IE to provide an action dependent
135  // on which submit button is clicked.
136  if ( $actionName === 'historysubmit' ) {
137  if ( $request->getBool( 'revisiondelete' ) ) {
138  $actionName = 'revisiondelete';
139  } elseif ( $request->getBool( 'editchangetags' ) ) {
140  $actionName = 'editchangetags';
141  } else {
142  $actionName = 'view';
143  }
144  } elseif ( $actionName === 'editredlink' ) {
145  $actionName = 'edit';
146  }
147 
148  // Trying to get a WikiPage for NS_SPECIAL etc. will result
149  // in WikiPage::factory throwing "Invalid or virtual namespace -1 given."
150  // For SpecialPages et al, default to action=view.
151  if ( !$context->canUseWikiPage() ) {
152  return 'view';
153  }
154 
155  $action = self::factory( $actionName, $context->getWikiPage(), $context );
156  if ( $action instanceof Action ) {
157  return $action->getName();
158  }
159 
160  return 'nosuchaction';
161  }
162 
170  final public static function exists( $name ) {
171  return self::getClass( $name, [] ) !== null;
172  }
173 
179  final public function getContext() {
180  if ( $this->context instanceof IContextSource ) {
181  return $this->context;
182  } elseif ( $this->page instanceof Article ) {
183  // NOTE: $this->page can be a WikiPage, which does not have a context.
184  wfDebug( __METHOD__ . ": no context known, falling back to Article's context.\n" );
185  return $this->page->getContext();
186  }
187 
188  wfWarn( __METHOD__ . ': no context known, falling back to RequestContext::getMain().' );
189  return RequestContext::getMain();
190  }
191 
198  final public function getRequest() {
199  return $this->getContext()->getRequest();
200  }
201 
208  final public function getOutput() {
209  return $this->getContext()->getOutput();
210  }
211 
218  final public function getUser() {
219  return $this->getContext()->getUser();
220  }
221 
228  final public function getSkin() {
229  return $this->getContext()->getSkin();
230  }
231 
237  final public function getLanguage() {
238  return $this->getContext()->getLanguage();
239  }
240 
247  final public function getTitle() {
248  return $this->page->getTitle();
249  }
250 
259  final public function msg( $key, ...$params ) {
260  return $this->getContext()->msg( $key, ...$params );
261  }
262 
269  public function __construct( Page $page, IContextSource $context = null ) {
270  if ( $context === null ) {
271  wfWarn( __METHOD__ . ' called without providing a Context object.' );
272  // NOTE: We could try to initialize $context using $page->getContext(),
273  // if $page is an Article. That however seems to not work seamlessly.
274  }
275 
276  $this->page = $page;
277  $this->context = $context;
278  }
279 
286  abstract public function getName();
287 
295  public function getRestriction() {
296  return null;
297  }
298 
308  protected function checkCanExecute( User $user ) {
309  $right = $this->getRestriction();
310  if ( $right !== null ) {
311  $errors = $this->getTitle()->getUserPermissionsErrors( $right, $user );
312  if ( count( $errors ) ) {
313  throw new PermissionsError( $right, $errors );
314  }
315  }
316 
317  // If the action requires an unblock, explicitly check the user's block.
318  if ( $this->requiresUnblock() && $user->isBlockedFrom( $this->getTitle() ) ) {
319  $block = $user->getBlock();
320  if ( $block ) {
321  throw new UserBlockedError(
322  $block,
323  $user,
324  $this->getLanguage(),
325  $this->getRequest()->getIP()
326  );
327  }
328 
329  throw new PermissionsError( $this->getName(), [ 'badaccess-group0' ] );
330  }
331 
332  // This should be checked at the end so that the user won't think the
333  // error is only temporary when he also don't have the rights to execute
334  // this action
335  if ( $this->requiresWrite() && wfReadOnly() ) {
336  throw new ReadOnlyError();
337  }
338  }
339 
346  public function requiresWrite() {
347  return true;
348  }
349 
356  public function requiresUnblock() {
357  return true;
358  }
359 
365  protected function setHeaders() {
366  $out = $this->getOutput();
367  $out->setRobotPolicy( 'noindex,nofollow' );
368  $out->setPageTitle( $this->getPageTitle() );
369  $out->setSubtitle( $this->getDescription() );
370  $out->setArticleRelated( true );
371  }
372 
378  protected function getPageTitle() {
379  return $this->getTitle()->getPrefixedText();
380  }
381 
388  protected function getDescription() {
389  return $this->msg( strtolower( $this->getName() ) )->escaped();
390  }
391 
400  public function addHelpLink( $to, $overrideBaseUrl = false ) {
401  $msg = wfMessage( MediaWikiServices::getInstance()->getContentLanguage()->lc(
402  self::getActionName( $this->getContext() )
403  ) . '-helppage' );
404 
405  if ( !$msg->isDisabled() ) {
406  $helpUrl = Skin::makeUrl( $msg->plain() );
407  $this->getOutput()->addHelpLink( $helpUrl, true );
408  } else {
409  $this->getOutput()->addHelpLink( $to, $overrideBaseUrl );
410  }
411  }
412 
421  abstract public function show();
422 
427  protected function useTransactionalTimeLimit() {
428  if ( $this->getRequest()->wasPosted() ) {
430  }
431  }
432 
438  public function doesWrites() {
439  return false;
440  }
441 }
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
getOutput()
Get the OutputPage being used for this instance.
Definition: Action.php:208
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: Action.php:400
getTitle()
Shortcut to get the Title object from the page.
Definition: Action.php:247
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
canUseWikiPage()
Check whether a WikiPage object can be get with getWikiPage().
static factory( $action, Page $page, IContextSource $context=null)
Get an appropriate Action subclass for the given action.
Definition: Action.php:97
getUser()
Shortcut to get the User being used for this instance.
Definition: Action.php:218
getBlock( $fromReplica=true)
Get the block affecting the user, or null if the user is not blocked.
Definition: User.php:2121
Class for viewing MediaWiki article and history.
Definition: Article.php:41
show()
The main action entry point.
getLanguage()
Shortcut to get the user Language being used for this instance.
Definition: Action.php:237
requiresUnblock()
Whether this action can still be executed by a blocked user.
Definition: Action.php:356
static exists( $name)
Check if a given action is recognised, even if it&#39;s disabled.
Definition: Action.php:170
getSkin()
Shortcut to get the Skin being used for this instance.
Definition: Action.php:228
doesWrites()
Indicates whether this action may perform database writes.
Definition: Action.php:438
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: Action.php:259
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: Action.php:427
$context
IContextSource if specified; otherwise we&#39;ll use the Context from the Page.
Definition: Action.php:53
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
Definition: Page.php:29
wfReadOnly()
Check whether the wiki is in read-only mode.
static getMain()
Get the RequestContext object associated with the main request.
getRestriction()
Get the permission required to perform this action.
Definition: Action.php:295
getName()
Return the name of the action this object responds to.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
setHeaders()
Set output headers for noindexing etc.
Definition: Action.php:365
isBlockedFrom( $title, $fromReplica=false)
Check if user is blocked from editing a particular article.
Definition: User.php:2137
getContext()
Get the IContextSource in use here.
Definition: Action.php:179
static getActionName(IContextSource $context)
Get the action that will be executed, not necessarily the one passed passed through the "action" requ...
Definition: Action.php:123
static getClass( $action, array $overrides)
Get the Action subclass which should be used to handle this action, false if the action is disabled...
Definition: Action.php:69
Show an error when the user tries to do something whilst blocked.
checkCanExecute(User $user)
Checks if the given user (identified by an object) can perform this action.
Definition: Action.php:308
$page
Page on which we&#39;re performing the action.
Definition: Action.php:46
$fields
The fields used to create the HTMLForm.
Definition: Action.php:60
static makeUrl( $name, $urlaction='')
Definition: Skin.php:1211
getDescription()
Returns the description that goes below the <h1> tag.
Definition: Action.php:388
getPageTitle()
Returns the name that goes in the <h1> page title.
Definition: Action.php:378
$wgActions
Array of allowed values for the "title=foo&action=<action>" parameter.
Show an error when a user tries to do something they do not have the necessary permissions for...
wfTransactionalTimeLimit()
Set PHP&#39;s time limit to the larger of php.ini or $wgTransactionalTimeLimit.
getWikiPage()
Get the WikiPage object.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
__construct(Page $page, IContextSource $context=null)
Only public since 1.21.
Definition: Action.php:269
getRequest()
Get the WebRequest being used for this instance.
Definition: Action.php:198
requiresWrite()
Whether this action requires the wiki not to be locked.
Definition: Action.php:346