summaryrefslogtreecommitdiff
path: root/includes/Action.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/Action.php')
-rw-r--r--includes/Action.php119
1 files changed, 73 insertions, 46 deletions
diff --git a/includes/Action.php b/includes/Action.php
index 51922251..4b6e4468 100644
--- a/includes/Action.php
+++ b/includes/Action.php
@@ -32,13 +32,13 @@
*
* Actions generally fall into two groups: the show-a-form-then-do-something-with-the-input
* format (protect, delete, move, etc), and the just-do-something format (watch, rollback,
- * patrol, etc). The FormAction and FormlessAction classes respresent these two groups.
+ * patrol, etc). The FormAction and FormlessAction classes represent these two groups.
*/
abstract class Action {
/**
* Page on which we're performing the action
- * @var Page $page
+ * @var WikiPage|Article|ImagePage|CategoryPage|Page $page
*/
protected $page;
@@ -59,9 +59,9 @@ abstract class Action {
* the action is disabled, or null if it's not recognised
* @param $action String
* @param $overrides Array
- * @return bool|null|string
+ * @return bool|null|string|callable
*/
- private final static function getClass( $action, array $overrides ) {
+ final private static function getClass( $action, array $overrides ) {
global $wgActions;
$action = strtolower( $action );
@@ -88,13 +88,19 @@ abstract class Action {
* @return Action|bool|null false if the action is disabled, null
* if it is not recognised
*/
- public final static function factory( $action, Page $page, IContextSource $context = null ) {
- $class = self::getClass( $action, $page->getActionOverrides() );
- if ( $class ) {
- $obj = new $class( $page, $context );
+ final public static function factory( $action, Page $page, IContextSource $context = null ) {
+ $classOrCallable = self::getClass( $action, $page->getActionOverrides() );
+
+ if ( is_string( $classOrCallable ) ) {
+ $obj = new $classOrCallable( $page, $context );
return $obj;
}
- return $class;
+
+ if ( is_callable( $classOrCallable ) ) {
+ return call_user_func_array( $classOrCallable, array( $page, $context ) );
+ }
+
+ return $classOrCallable;
}
/**
@@ -106,7 +112,7 @@ abstract class Action {
* @param $context IContextSource
* @return string: action name
*/
- public final static function getActionName( IContextSource $context ) {
+ final public static function getActionName( IContextSource $context ) {
global $wgActions;
$request = $context->getRequest();
@@ -136,7 +142,7 @@ abstract class Action {
return 'view';
}
- $action = Action::factory( $actionName, $context->getWikiPage() );
+ $action = Action::factory( $actionName, $context->getWikiPage(), $context );
if ( $action instanceof Action ) {
return $action->getName();
}
@@ -147,10 +153,10 @@ abstract class Action {
/**
* Check if a given action is recognised, even if it's disabled
*
- * @param $name String: name of an action
+ * @param string $name name of an action
* @return Bool
*/
- public final static function exists( $name ) {
+ final public static function exists( $name ) {
return self::getClass( $name, array() ) !== null;
}
@@ -158,11 +164,17 @@ abstract class Action {
* Get the IContextSource in use here
* @return IContextSource
*/
- public final function getContext() {
+ final public function getContext() {
if ( $this->context instanceof IContextSource ) {
return $this->context;
+ } else if ( $this->page instanceof Article ) {
+ // NOTE: $this->page can be a WikiPage, which does not have a context.
+ wfDebug( __METHOD__ . ': no context known, falling back to Article\'s context.' );
+ return $this->page->getContext();
}
- return $this->page->getContext();
+
+ wfWarn( __METHOD__ . ': no context known, falling back to RequestContext::getMain().' );
+ return RequestContext::getMain();
}
/**
@@ -170,7 +182,7 @@ abstract class Action {
*
* @return WebRequest
*/
- public final function getRequest() {
+ final public function getRequest() {
return $this->getContext()->getRequest();
}
@@ -179,7 +191,7 @@ abstract class Action {
*
* @return OutputPage
*/
- public final function getOutput() {
+ final public function getOutput() {
return $this->getContext()->getOutput();
}
@@ -188,7 +200,7 @@ abstract class Action {
*
* @return User
*/
- public final function getUser() {
+ final public function getUser() {
return $this->getContext()->getUser();
}
@@ -197,7 +209,7 @@ abstract class Action {
*
* @return Skin
*/
- public final function getSkin() {
+ final public function getSkin() {
return $this->getContext()->getSkin();
}
@@ -206,17 +218,17 @@ abstract class Action {
*
* @return Language
*/
- public final function getLanguage() {
+ final public function getLanguage() {
return $this->getContext()->getLanguage();
}
/**
* Shortcut to get the user Language being used for this instance
*
- * @deprecated 1.19 Use getLanguage instead
+ * @deprecated since 1.19 Use getLanguage instead
* @return Language
*/
- public final function getLang() {
+ final public function getLang() {
wfDeprecated( __METHOD__, '1.19' );
return $this->getLanguage();
}
@@ -225,7 +237,7 @@ abstract class Action {
* Shortcut to get the Title object from the page
* @return Title
*/
- public final function getTitle() {
+ final public function getTitle() {
return $this->page->getTitle();
}
@@ -235,18 +247,26 @@ abstract class Action {
*
* @return Message object
*/
- public final function msg() {
+ final public function msg() {
$params = func_get_args();
return call_user_func_array( array( $this->getContext(), 'msg' ), $params );
}
/**
- * Protected constructor: use Action::factory( $action, $page ) to actually build
- * these things in the real world
+ * Constructor.
+ *
+ * Only public since 1.21
+ *
* @param $page Page
* @param $context IContextSource
*/
- protected function __construct( Page $page, IContextSource $context = null ) {
+ public function __construct( Page $page, IContextSource $context = null ) {
+ if ( $context === null ) {
+ wfWarn( __METHOD__ . ' called without providing a Context object.' );
+ // NOTE: We could try to initialize $context using $page->getContext(),
+ // if $page is an Article. That however seems to not work seamlessly.
+ }
+
$this->page = $page;
$this->context = $context;
}
@@ -255,7 +275,7 @@ abstract class Action {
* Return the name of the action this object responds to
* @return String lowercase
*/
- public abstract function getName();
+ abstract public function getName();
/**
* Get the permission required to perform this action. Often, but not always,
@@ -272,7 +292,7 @@ abstract class Action {
* must throw subclasses of ErrorPageError
*
* @param $user User: the user to check, or null to use the context user
- * @throws ErrorPageError
+ * @throws UserBlockedError|ReadOnlyError|PermissionsError
* @return bool True on success
*/
protected function checkCanExecute( User $user ) {
@@ -350,13 +370,13 @@ abstract class Action {
* $this->getOutput(), etc.
* @throws ErrorPageError
*/
- public abstract function show();
+ abstract public function show();
/**
* Execute the action in a silent fashion: do not display anything or release any errors.
* @return Bool whether execution was successful
*/
- public abstract function execute();
+ abstract public function execute();
}
/**
@@ -368,27 +388,32 @@ abstract class FormAction extends Action {
* Get an HTMLForm descriptor array
* @return Array
*/
- protected abstract function getFormFields();
+ abstract protected function getFormFields();
/**
* Add pre- or post-text to the form
* @return String HTML which will be sent to $form->addPreText()
*/
- protected function preText() { return ''; }
+ protected function preText() {
+ return '';
+ }
/**
* @return string
*/
- protected function postText() { return ''; }
+ protected function postText() {
+ return '';
+ }
/**
* Play with the HTMLForm if you need to more substantially
* @param $form HTMLForm
*/
- protected function alterForm( HTMLForm $form ) {}
+ protected function alterForm( HTMLForm $form ) {
+ }
/**
- * Get the HTMLForm to control behaviour
+ * Get the HTMLForm to control behavior
* @return HTMLForm|null
*/
protected function getForm() {
@@ -406,7 +431,7 @@ abstract class FormAction extends Action {
$this->getRequest()->getQueryValues(),
array( 'action' => null, 'title' => null )
);
- $form->addHiddenField( 'redirectparams', wfArrayToCGI( $params ) );
+ $form->addHiddenField( 'redirectparams', wfArrayToCgi( $params ) );
$form->addPreText( $this->preText() );
$form->addPostText( $this->postText() );
@@ -425,21 +450,21 @@ abstract class FormAction extends Action {
* @param $data Array
* @return Bool|Array true for success, false for didn't-try, array of errors on failure
*/
- public abstract function onSubmit( $data );
+ abstract public function onSubmit( $data );
/**
* Do something exciting on successful processing of the form. This might be to show
* a confirmation message (watch, rollback, etc) or to redirect somewhere else (edit,
* protect, etc).
*/
- public abstract function onSuccess();
+ abstract public function onSuccess();
/**
* The basic pattern for actions is to display some sort of HTMLForm UI, maybe with
* some stuff underneath (history etc); to do some processing on submission of that
* form (delete, protect, etc) and to do something exciting on 'success', be that
* display something new or redirect to somewhere. Some actions have more exotic
- * behaviour, but that's what subclassing is for :D
+ * behavior, but that's what subclassing is for :D
*/
public function show() {
$this->setHeaders();
@@ -455,15 +480,16 @@ abstract class FormAction extends Action {
/**
* @see Action::execute()
- * @throws ErrorPageError
+ *
* @param $data array|null
* @param $captureErrors bool
+ * @throws ErrorPageError|Exception
* @return bool
*/
public function execute( array $data = null, $captureErrors = true ) {
try {
// Set a new context so output doesn't leak.
- $this->context = clone $this->page->getContext();
+ $this->context = clone $this->getContext();
// This will throw exceptions if there's a problem
$this->checkCanExecute( $this->getUser() );
@@ -507,7 +533,7 @@ abstract class FormlessAction extends Action {
* @return String|null will be added to the HTMLForm if present, or just added to the
* output if not. Return null to not add anything
*/
- public abstract function onView();
+ abstract public function onView();
/**
* We don't want an HTMLForm
@@ -544,14 +570,15 @@ abstract class FormlessAction extends Action {
/**
* Execute the action silently, not giving any output. Since these actions don't have
* forms, they probably won't have any data, but some (eg rollback) may do
- * @param $data Array values that would normally be in the GET request
- * @param $captureErrors Bool whether to catch exceptions and just return false
+ * @param array $data values that would normally be in the GET request
+ * @param bool $captureErrors whether to catch exceptions and just return false
+ * @throws ErrorPageError|Exception
* @return Bool whether execution was successful
*/
public function execute( array $data = null, $captureErrors = true ) {
try {
// Set a new context so output doesn't leak.
- $this->context = clone $this->page->getContext();
+ $this->context = clone $this->getContext();
if ( is_array( $data ) ) {
$this->context->setRequest( new FauxRequest( $data, false ) );
}