[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Base classes for actions done on pages. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 18 * 19 * @file 20 */ 21 22 /** 23 * @defgroup Actions Action done on pages 24 */ 25 26 /** 27 * Actions are things which can be done to pages (edit, delete, rollback, etc). They 28 * are distinct from Special Pages because an action must apply to exactly one page. 29 * 30 * To add an action in an extension, create a subclass of Action, and add the key to 31 * $wgActions. There is also the deprecated UnknownAction hook 32 * 33 * Actions generally fall into two groups: the show-a-form-then-do-something-with-the-input 34 * format (protect, delete, move, etc), and the just-do-something format (watch, rollback, 35 * patrol, etc). The FormAction and FormlessAction classes represent these two groups. 36 */ 37 abstract class Action { 38 39 /** 40 * Page on which we're performing the action 41 * @since 1.17 42 * @var WikiPage|Article|ImagePage|CategoryPage|Page $page 43 */ 44 protected $page; 45 46 /** 47 * IContextSource if specified; otherwise we'll use the Context from the Page 48 * @since 1.17 49 * @var IContextSource $context 50 */ 51 protected $context; 52 53 /** 54 * The fields used to create the HTMLForm 55 * @since 1.17 56 * @var array $fields 57 */ 58 protected $fields; 59 60 /** 61 * Get the Action subclass which should be used to handle this action, false if 62 * the action is disabled, or null if it's not recognised 63 * @param string $action 64 * @param array $overrides 65 * @return bool|null|string|callable 66 */ 67 final private static function getClass( $action, array $overrides ) { 68 global $wgActions; 69 $action = strtolower( $action ); 70 71 if ( !isset( $wgActions[$action] ) ) { 72 return null; 73 } 74 75 if ( $wgActions[$action] === false ) { 76 return false; 77 } elseif ( $wgActions[$action] === true && isset( $overrides[$action] ) ) { 78 return $overrides[$action]; 79 } elseif ( $wgActions[$action] === true ) { 80 return ucfirst( $action ) . 'Action'; 81 } else { 82 return $wgActions[$action]; 83 } 84 } 85 86 /** 87 * Get an appropriate Action subclass for the given action 88 * @since 1.17 89 * @param string $action 90 * @param Page $page 91 * @param IContextSource $context 92 * @return Action|bool|null False if the action is disabled, null 93 * if it is not recognised 94 */ 95 final public static function factory( $action, Page $page, IContextSource $context = null ) { 96 $classOrCallable = self::getClass( $action, $page->getActionOverrides() ); 97 98 if ( is_string( $classOrCallable ) ) { 99 $obj = new $classOrCallable( $page, $context ); 100 return $obj; 101 } 102 103 if ( is_callable( $classOrCallable ) ) { 104 return call_user_func_array( $classOrCallable, array( $page, $context ) ); 105 } 106 107 return $classOrCallable; 108 } 109 110 /** 111 * Get the action that will be executed, not necessarily the one passed 112 * passed through the "action" request parameter. Actions disabled in 113 * $wgActions will be replaced by "nosuchaction". 114 * 115 * @since 1.19 116 * @param IContextSource $context 117 * @return string Action name 118 */ 119 final public static function getActionName( IContextSource $context ) { 120 global $wgActions; 121 122 $request = $context->getRequest(); 123 $actionName = $request->getVal( 'action', 'view' ); 124 125 // Check for disabled actions 126 if ( isset( $wgActions[$actionName] ) && $wgActions[$actionName] === false ) { 127 $actionName = 'nosuchaction'; 128 } 129 130 // Workaround for bug #20966: inability of IE to provide an action dependent 131 // on which submit button is clicked. 132 if ( $actionName === 'historysubmit' ) { 133 if ( $request->getBool( 'revisiondelete' ) ) { 134 $actionName = 'revisiondelete'; 135 } else { 136 $actionName = 'view'; 137 } 138 } elseif ( $actionName == 'editredlink' ) { 139 $actionName = 'edit'; 140 } 141 142 // Trying to get a WikiPage for NS_SPECIAL etc. will result 143 // in WikiPage::factory throwing "Invalid or virtual namespace -1 given." 144 // For SpecialPages et al, default to action=view. 145 if ( !$context->canUseWikiPage() ) { 146 return 'view'; 147 } 148 149 $action = Action::factory( $actionName, $context->getWikiPage(), $context ); 150 if ( $action instanceof Action ) { 151 return $action->getName(); 152 } 153 154 return 'nosuchaction'; 155 } 156 157 /** 158 * Check if a given action is recognised, even if it's disabled 159 * @since 1.17 160 * 161 * @param string $name Name of an action 162 * @return bool 163 */ 164 final public static function exists( $name ) { 165 return self::getClass( $name, array() ) !== null; 166 } 167 168 /** 169 * Get the IContextSource in use here 170 * @since 1.17 171 * @return IContextSource 172 */ 173 final public function getContext() { 174 if ( $this->context instanceof IContextSource ) { 175 return $this->context; 176 } elseif ( $this->page instanceof Article ) { 177 // NOTE: $this->page can be a WikiPage, which does not have a context. 178 wfDebug( __METHOD__ . ": no context known, falling back to Article's context.\n" ); 179 return $this->page->getContext(); 180 } 181 182 wfWarn( __METHOD__ . ': no context known, falling back to RequestContext::getMain().' ); 183 return RequestContext::getMain(); 184 } 185 186 /** 187 * Get the WebRequest being used for this instance 188 * @since 1.17 189 * 190 * @return WebRequest 191 */ 192 final public function getRequest() { 193 return $this->getContext()->getRequest(); 194 } 195 196 /** 197 * Get the OutputPage being used for this instance 198 * @since 1.17 199 * 200 * @return OutputPage 201 */ 202 final public function getOutput() { 203 return $this->getContext()->getOutput(); 204 } 205 206 /** 207 * Shortcut to get the User being used for this instance 208 * @since 1.17 209 * 210 * @return User 211 */ 212 final public function getUser() { 213 return $this->getContext()->getUser(); 214 } 215 216 /** 217 * Shortcut to get the Skin being used for this instance 218 * @since 1.17 219 * 220 * @return Skin 221 */ 222 final public function getSkin() { 223 return $this->getContext()->getSkin(); 224 } 225 226 /** 227 * Shortcut to get the user Language being used for this instance 228 * 229 * @return Language 230 */ 231 final public function getLanguage() { 232 return $this->getContext()->getLanguage(); 233 } 234 235 /** 236 * Shortcut to get the Title object from the page 237 * @since 1.17 238 * 239 * @return Title 240 */ 241 final public function getTitle() { 242 return $this->page->getTitle(); 243 } 244 245 /** 246 * Get a Message object with context set 247 * Parameters are the same as wfMessage() 248 * 249 * @return Message 250 */ 251 final public function msg() { 252 $params = func_get_args(); 253 return call_user_func_array( array( $this->getContext(), 'msg' ), $params ); 254 } 255 256 /** 257 * Constructor. 258 * 259 * Only public since 1.21 260 * 261 * @param Page $page 262 * @param IContextSource $context 263 */ 264 public function __construct( Page $page, IContextSource $context = null ) { 265 if ( $context === null ) { 266 wfWarn( __METHOD__ . ' called without providing a Context object.' ); 267 // NOTE: We could try to initialize $context using $page->getContext(), 268 // if $page is an Article. That however seems to not work seamlessly. 269 } 270 271 $this->page = $page; 272 $this->context = $context; 273 } 274 275 /** 276 * Return the name of the action this object responds to 277 * @since 1.17 278 * 279 * @return string Lowercase name 280 */ 281 abstract public function getName(); 282 283 /** 284 * Get the permission required to perform this action. Often, but not always, 285 * the same as the action name 286 * @since 1.17 287 * 288 * @return string|null 289 */ 290 public function getRestriction() { 291 return null; 292 } 293 294 /** 295 * Checks if the given user (identified by an object) can perform this action. Can be 296 * overridden by sub-classes with more complicated permissions schemes. Failures here 297 * must throw subclasses of ErrorPageError 298 * @since 1.17 299 * 300 * @param User $user The user to check, or null to use the context user 301 * @throws UserBlockedError|ReadOnlyError|PermissionsError 302 */ 303 protected function checkCanExecute( User $user ) { 304 $right = $this->getRestriction(); 305 if ( $right !== null ) { 306 $errors = $this->getTitle()->getUserPermissionsErrors( $right, $user ); 307 if ( count( $errors ) ) { 308 throw new PermissionsError( $right, $errors ); 309 } 310 } 311 312 if ( $this->requiresUnblock() && $user->isBlocked() ) { 313 $block = $user->getBlock(); 314 throw new UserBlockedError( $block ); 315 } 316 317 // This should be checked at the end so that the user won't think the 318 // error is only temporary when he also don't have the rights to execute 319 // this action 320 if ( $this->requiresWrite() && wfReadOnly() ) { 321 throw new ReadOnlyError(); 322 } 323 } 324 325 /** 326 * Whether this action requires the wiki not to be locked 327 * @since 1.17 328 * 329 * @return bool 330 */ 331 public function requiresWrite() { 332 return true; 333 } 334 335 /** 336 * Whether this action can still be executed by a blocked user 337 * @since 1.17 338 * 339 * @return bool 340 */ 341 public function requiresUnblock() { 342 return true; 343 } 344 345 /** 346 * Set output headers for noindexing etc. This function will not be called through 347 * the execute() entry point, so only put UI-related stuff in here. 348 * @since 1.17 349 */ 350 protected function setHeaders() { 351 $out = $this->getOutput(); 352 $out->setRobotPolicy( "noindex,nofollow" ); 353 $out->setPageTitle( $this->getPageTitle() ); 354 $out->setSubtitle( $this->getDescription() ); 355 $out->setArticleRelated( true ); 356 } 357 358 /** 359 * Returns the name that goes in the \<h1\> page title 360 * 361 * @return string 362 */ 363 protected function getPageTitle() { 364 return $this->getTitle()->getPrefixedText(); 365 } 366 367 /** 368 * Returns the description that goes below the \<h1\> tag 369 * @since 1.17 370 * 371 * @return string 372 */ 373 protected function getDescription() { 374 return $this->msg( strtolower( $this->getName() ) )->escaped(); 375 } 376 377 /** 378 * The main action entry point. Do all output for display and send it to the context 379 * output. Do not use globals $wgOut, $wgRequest, etc, in implementations; use 380 * $this->getOutput(), etc. 381 * @since 1.17 382 * 383 * @throws ErrorPageError 384 */ 385 abstract public function show(); 386 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |