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 
257  final public function msg( $key ) {
258  $params = func_get_args();
259  return $this->getContext()->msg( ...$params );
260  }
261 
268  public function __construct( Page $page, IContextSource $context = null ) {
269  if ( $context === null ) {
270  wfWarn( __METHOD__ . ' called without providing a Context object.' );
271  // NOTE: We could try to initialize $context using $page->getContext(),
272  // if $page is an Article. That however seems to not work seamlessly.
273  }
274 
275  $this->page = $page;
276  $this->context = $context;
277  }
278 
285  abstract public function getName();
286 
294  public function getRestriction() {
295  return null;
296  }
297 
307  protected function checkCanExecute( User $user ) {
308  $right = $this->getRestriction();
309  if ( $right !== null ) {
310  $errors = $this->getTitle()->getUserPermissionsErrors( $right, $user );
311  if ( count( $errors ) ) {
312  throw new PermissionsError( $right, $errors );
313  }
314  }
315 
316  // If the action requires an unblock, explicitly check the user's block.
317  if ( $this->requiresUnblock() && $user->isBlockedFrom( $this->getTitle() ) ) {
318  $block = $user->getBlock();
319  if ( $block ) {
320  throw new UserBlockedError( $block );
321  }
322 
323  throw new PermissionsError( $this->getName(), [ 'badaccess-group0' ] );
324  }
325 
326  // This should be checked at the end so that the user won't think the
327  // error is only temporary when he also don't have the rights to execute
328  // this action
329  if ( $this->requiresWrite() && wfReadOnly() ) {
330  throw new ReadOnlyError();
331  }
332  }
333 
340  public function requiresWrite() {
341  return true;
342  }
343 
350  public function requiresUnblock() {
351  return true;
352  }
353 
359  protected function setHeaders() {
360  $out = $this->getOutput();
361  $out->setRobotPolicy( 'noindex,nofollow' );
362  $out->setPageTitle( $this->getPageTitle() );
363  $out->setSubtitle( $this->getDescription() );
364  $out->setArticleRelated( true );
365  }
366 
372  protected function getPageTitle() {
373  return $this->getTitle()->getPrefixedText();
374  }
375 
382  protected function getDescription() {
383  return $this->msg( strtolower( $this->getName() ) )->escaped();
384  }
385 
394  public function addHelpLink( $to, $overrideBaseUrl = false ) {
395  $msg = wfMessage( MediaWikiServices::getInstance()->getContentLanguage()->lc(
396  self::getActionName( $this->getContext() )
397  ) . '-helppage' );
398 
399  if ( !$msg->isDisabled() ) {
400  $helpUrl = Skin::makeUrl( $msg->plain() );
401  $this->getOutput()->addHelpLink( $helpUrl, true );
402  } else {
403  $this->getOutput()->addHelpLink( $to, $overrideBaseUrl );
404  }
405  }
406 
415  abstract public function show();
416 
421  protected function useTransactionalTimeLimit() {
422  if ( $this->getRequest()->wasPosted() ) {
424  }
425  }
426 
432  public function doesWrites() {
433  return false;
434  }
435 }
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:394
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:2068
Class for viewing MediaWiki article and history.
Definition: Article.php:38
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:350
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:432
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: Action.php:421
$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:294
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:359
isBlockedFrom( $title, $fromReplica=false)
Check if user is blocked from editing a particular article.
Definition: User.php:2084
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:307
$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:1217
getDescription()
Returns the description that goes below the <h1> tag.
Definition: Action.php:382
getPageTitle()
Returns the name that goes in the <h1> page title.
Definition: Action.php:372
$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:268
msg( $key)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: Action.php:257
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:340