Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WikiPage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WikiPage, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 32 | class WikiPage implements Page, IDBAccessObject { | 
            ||
| 33 | // Constants for $mDataLoadedFrom and related  | 
            ||
| 34 | |||
| 35 | /**  | 
            ||
| 36 | * @var Title  | 
            ||
| 37 | */  | 
            ||
| 38 | public $mTitle = null;  | 
            ||
| 39 | |||
| 40 | 	/**@{{ | 
            ||
| 41 | * @protected  | 
            ||
| 42 | */  | 
            ||
| 43 | public $mDataLoaded = false; // !< Boolean  | 
            ||
| 44 | public $mIsRedirect = false; // !< Boolean  | 
            ||
| 45 | public $mLatest = false; // !< Integer (false means "not loaded")  | 
            ||
| 46 | /**@}}*/  | 
            ||
| 47 | |||
| 48 | /** @var stdClass Map of cache fields (text, parser output, ect) for a proposed/new edit */  | 
            ||
| 49 | public $mPreparedEdit = false;  | 
            ||
| 50 | |||
| 51 | /**  | 
            ||
| 52 | * @var int  | 
            ||
| 53 | */  | 
            ||
| 54 | protected $mId = null;  | 
            ||
| 55 | |||
| 56 | /**  | 
            ||
| 57 | * @var int One of the READ_* constants  | 
            ||
| 58 | */  | 
            ||
| 59 | protected $mDataLoadedFrom = self::READ_NONE;  | 
            ||
| 60 | |||
| 61 | /**  | 
            ||
| 62 | * @var Title  | 
            ||
| 63 | */  | 
            ||
| 64 | protected $mRedirectTarget = null;  | 
            ||
| 65 | |||
| 66 | /**  | 
            ||
| 67 | * @var Revision  | 
            ||
| 68 | */  | 
            ||
| 69 | protected $mLastRevision = null;  | 
            ||
| 70 | |||
| 71 | /**  | 
            ||
| 72 | * @var string Timestamp of the current revision or empty string if not loaded  | 
            ||
| 73 | */  | 
            ||
| 74 | protected $mTimestamp = '';  | 
            ||
| 75 | |||
| 76 | /**  | 
            ||
| 77 | * @var string  | 
            ||
| 78 | */  | 
            ||
| 79 | protected $mTouched = '19700101000000';  | 
            ||
| 80 | |||
| 81 | /**  | 
            ||
| 82 | * @var string  | 
            ||
| 83 | */  | 
            ||
| 84 | protected $mLinksUpdated = '19700101000000';  | 
            ||
| 85 | |||
| 86 | const PURGE_CDN_CACHE = 1; // purge CDN cache for page variant URLs  | 
            ||
| 87 | const PURGE_CLUSTER_PCACHE = 2; // purge parser cache in the local datacenter  | 
            ||
| 88 | const PURGE_GLOBAL_PCACHE = 4; // set page_touched to clear parser cache in all datacenters  | 
            ||
| 89 | const PURGE_ALL = 7;  | 
            ||
| 90 | |||
| 91 | /**  | 
            ||
| 92 | * Constructor and clear the article  | 
            ||
| 93 | * @param Title $title Reference to a Title object.  | 
            ||
| 94 | */  | 
            ||
| 95 | 	public function __construct( Title $title ) { | 
            ||
| 98 | |||
| 99 | /**  | 
            ||
| 100 | * Makes sure that the mTitle object is cloned  | 
            ||
| 101 | * to the newly cloned WikiPage.  | 
            ||
| 102 | */  | 
            ||
| 103 | 	public function __clone() { | 
            ||
| 106 | |||
| 107 | /**  | 
            ||
| 108 | * Create a WikiPage object of the appropriate class for the given title.  | 
            ||
| 109 | *  | 
            ||
| 110 | * @param Title $title  | 
            ||
| 111 | *  | 
            ||
| 112 | * @throws MWException  | 
            ||
| 113 | * @return WikiPage|WikiCategoryPage|WikiFilePage  | 
            ||
| 114 | */  | 
            ||
| 115 | 	public static function factory( Title $title ) { | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * Constructor from a page id  | 
            ||
| 140 | *  | 
            ||
| 141 | * @param int $id Article ID to load  | 
            ||
| 142 | * @param string|int $from One of the following values:  | 
            ||
| 143 | * - "fromdb" or WikiPage::READ_NORMAL to select from a replica DB  | 
            ||
| 144 | * - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database  | 
            ||
| 145 | *  | 
            ||
| 146 | * @return WikiPage|null  | 
            ||
| 147 | */  | 
            ||
| 148 | 	public static function newFromID( $id, $from = 'fromdb' ) { | 
            ||
| 163 | |||
| 164 | /**  | 
            ||
| 165 | * Constructor from a database row  | 
            ||
| 166 | *  | 
            ||
| 167 | * @since 1.20  | 
            ||
| 168 | * @param object $row Database row containing at least fields returned by selectFields().  | 
            ||
| 169 | * @param string|int $from Source of $data:  | 
            ||
| 170 | * - "fromdb" or WikiPage::READ_NORMAL: from a replica DB  | 
            ||
| 171 | * - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB  | 
            ||
| 172 | * - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE  | 
            ||
| 173 | * @return WikiPage  | 
            ||
| 174 | */  | 
            ||
| 175 | 	public static function newFromRow( $row, $from = 'fromdb' ) { | 
            ||
| 180 | |||
| 181 | /**  | 
            ||
| 182 | * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to READ_* constants.  | 
            ||
| 183 | *  | 
            ||
| 184 | * @param object|string|int $type  | 
            ||
| 185 | * @return mixed  | 
            ||
| 186 | */  | 
            ||
| 187 | 	private static function convertSelectType( $type ) { | 
            ||
| 200 | |||
| 201 | /**  | 
            ||
| 202 | * @todo Move this UI stuff somewhere else  | 
            ||
| 203 | *  | 
            ||
| 204 | * @see ContentHandler::getActionOverrides  | 
            ||
| 205 | */  | 
            ||
| 206 | 	public function getActionOverrides() { | 
            ||
| 209 | |||
| 210 | /**  | 
            ||
| 211 | * Returns the ContentHandler instance to be used to deal with the content of this WikiPage.  | 
            ||
| 212 | *  | 
            ||
| 213 | * Shorthand for ContentHandler::getForModelID( $this->getContentModel() );  | 
            ||
| 214 | *  | 
            ||
| 215 | * @return ContentHandler  | 
            ||
| 216 | *  | 
            ||
| 217 | * @since 1.21  | 
            ||
| 218 | */  | 
            ||
| 219 | 	public function getContentHandler() { | 
            ||
| 222 | |||
| 223 | /**  | 
            ||
| 224 | * Get the title object of the article  | 
            ||
| 225 | * @return Title Title object of this page  | 
            ||
| 226 | */  | 
            ||
| 227 | 	public function getTitle() { | 
            ||
| 230 | |||
| 231 | /**  | 
            ||
| 232 | * Clear the object  | 
            ||
| 233 | * @return void  | 
            ||
| 234 | */  | 
            ||
| 235 | 	public function clear() { | 
            ||
| 241 | |||
| 242 | /**  | 
            ||
| 243 | * Clear the object cache fields  | 
            ||
| 244 | * @return void  | 
            ||
| 245 | */  | 
            ||
| 246 | 	protected function clearCacheFields() { | 
            ||
| 260 | |||
| 261 | /**  | 
            ||
| 262 | * Clear the mPreparedEdit cache field, as may be needed by mutable content types  | 
            ||
| 263 | * @return void  | 
            ||
| 264 | * @since 1.23  | 
            ||
| 265 | */  | 
            ||
| 266 | 	public function clearPreparedEdit() { | 
            ||
| 269 | |||
| 270 | /**  | 
            ||
| 271 | * Return the list of revision fields that should be selected to create  | 
            ||
| 272 | * a new page.  | 
            ||
| 273 | *  | 
            ||
| 274 | * @return array  | 
            ||
| 275 | */  | 
            ||
| 276 | 	public static function selectFields() { | 
            ||
| 303 | |||
| 304 | /**  | 
            ||
| 305 | * Fetch a page record with the given conditions  | 
            ||
| 306 | * @param IDatabase $dbr  | 
            ||
| 307 | * @param array $conditions  | 
            ||
| 308 | * @param array $options  | 
            ||
| 309 | * @return object|bool Database result resource, or false on failure  | 
            ||
| 310 | */  | 
            ||
| 311 | 	protected function pageData( $dbr, $conditions, $options = [] ) { | 
            ||
| 322 | |||
| 323 | /**  | 
            ||
| 324 | * Fetch a page record matching the Title object's namespace and title  | 
            ||
| 325 | * using a sanitized title string  | 
            ||
| 326 | *  | 
            ||
| 327 | * @param IDatabase $dbr  | 
            ||
| 328 | * @param Title $title  | 
            ||
| 329 | * @param array $options  | 
            ||
| 330 | * @return object|bool Database result resource, or false on failure  | 
            ||
| 331 | */  | 
            ||
| 332 | 	public function pageDataFromTitle( $dbr, $title, $options = [] ) { | 
            ||
| 337 | |||
| 338 | /**  | 
            ||
| 339 | * Fetch a page record matching the requested ID  | 
            ||
| 340 | *  | 
            ||
| 341 | * @param IDatabase $dbr  | 
            ||
| 342 | * @param int $id  | 
            ||
| 343 | * @param array $options  | 
            ||
| 344 | * @return object|bool Database result resource, or false on failure  | 
            ||
| 345 | */  | 
            ||
| 346 | 	public function pageDataFromId( $dbr, $id, $options = [] ) { | 
            ||
| 349 | |||
| 350 | /**  | 
            ||
| 351 | * Load the object from a given source by title  | 
            ||
| 352 | *  | 
            ||
| 353 | * @param object|string|int $from One of the following:  | 
            ||
| 354 | * - A DB query result object.  | 
            ||
| 355 | * - "fromdb" or WikiPage::READ_NORMAL to get from a replica DB.  | 
            ||
| 356 | * - "fromdbmaster" or WikiPage::READ_LATEST to get from the master DB.  | 
            ||
| 357 | * - "forupdate" or WikiPage::READ_LOCKING to get from the master DB  | 
            ||
| 358 | * using SELECT FOR UPDATE.  | 
            ||
| 359 | *  | 
            ||
| 360 | * @return void  | 
            ||
| 361 | */  | 
            ||
| 362 | 	public function loadPageData( $from = 'fromdb' ) { | 
            ||
| 390 | |||
| 391 | /**  | 
            ||
| 392 | * Load the object from a database row  | 
            ||
| 393 | *  | 
            ||
| 394 | * @since 1.20  | 
            ||
| 395 | * @param object|bool $data DB row containing fields returned by selectFields() or false  | 
            ||
| 396 | * @param string|int $from One of the following:  | 
            ||
| 397 | * - "fromdb" or WikiPage::READ_NORMAL if the data comes from a replica DB  | 
            ||
| 398 | * - "fromdbmaster" or WikiPage::READ_LATEST if the data comes from the master DB  | 
            ||
| 399 | * - "forupdate" or WikiPage::READ_LOCKING if the data comes from  | 
            ||
| 400 | * the master DB using SELECT FOR UPDATE  | 
            ||
| 401 | */  | 
            ||
| 402 | 	public function loadFromRow( $data, $from ) { | 
            ||
| 438 | |||
| 439 | /**  | 
            ||
| 440 | * @return int Page ID  | 
            ||
| 441 | */  | 
            ||
| 442 | 	public function getId() { | 
            ||
| 448 | |||
| 449 | /**  | 
            ||
| 450 | * @return bool Whether or not the page exists in the database  | 
            ||
| 451 | */  | 
            ||
| 452 | 	public function exists() { | 
            ||
| 458 | |||
| 459 | /**  | 
            ||
| 460 | * Check if this page is something we're going to be showing  | 
            ||
| 461 | * some sort of sensible content for. If we return false, page  | 
            ||
| 462 | * views (plain action=view) will return an HTTP 404 response,  | 
            ||
| 463 | * so spiders and robots can know they're following a bad link.  | 
            ||
| 464 | *  | 
            ||
| 465 | * @return bool  | 
            ||
| 466 | */  | 
            ||
| 467 | 	public function hasViewableContent() { | 
            ||
| 470 | |||
| 471 | /**  | 
            ||
| 472 | * Tests if the article content represents a redirect  | 
            ||
| 473 | *  | 
            ||
| 474 | * @return bool  | 
            ||
| 475 | */  | 
            ||
| 476 | 	public function isRedirect() { | 
            ||
| 483 | |||
| 484 | /**  | 
            ||
| 485 | * Returns the page's content model id (see the CONTENT_MODEL_XXX constants).  | 
            ||
| 486 | *  | 
            ||
| 487 | * Will use the revisions actual content model if the page exists,  | 
            ||
| 488 | * and the page's default if the page doesn't exist yet.  | 
            ||
| 489 | *  | 
            ||
| 490 | * @return string  | 
            ||
| 491 | *  | 
            ||
| 492 | * @since 1.21  | 
            ||
| 493 | */  | 
            ||
| 494 | 	public function getContentModel() { | 
            ||
| 518 | |||
| 519 | /**  | 
            ||
| 520 | * Loads page_touched and returns a value indicating if it should be used  | 
            ||
| 521 | * @return bool True if this page exists and is not a redirect  | 
            ||
| 522 | */  | 
            ||
| 523 | 	public function checkTouched() { | 
            ||
| 529 | |||
| 530 | /**  | 
            ||
| 531 | * Get the page_touched field  | 
            ||
| 532 | * @return string Containing GMT timestamp  | 
            ||
| 533 | */  | 
            ||
| 534 | 	public function getTouched() { | 
            ||
| 540 | |||
| 541 | /**  | 
            ||
| 542 | * Get the page_links_updated field  | 
            ||
| 543 | * @return string|null Containing GMT timestamp  | 
            ||
| 544 | */  | 
            ||
| 545 | 	public function getLinksTimestamp() { | 
            ||
| 551 | |||
| 552 | /**  | 
            ||
| 553 | * Get the page_latest field  | 
            ||
| 554 | * @return int The rev_id of current revision  | 
            ||
| 555 | */  | 
            ||
| 556 | 	public function getLatest() { | 
            ||
| 562 | |||
| 563 | /**  | 
            ||
| 564 | * Get the Revision object of the oldest revision  | 
            ||
| 565 | * @return Revision|null  | 
            ||
| 566 | */  | 
            ||
| 567 | 	public function getOldestRevision() { | 
            ||
| 600 | |||
| 601 | /**  | 
            ||
| 602 | * Loads everything except the text  | 
            ||
| 603 | * This isn't necessary for all uses, so it's only done if needed.  | 
            ||
| 604 | */  | 
            ||
| 605 | 	protected function loadLastEdit() { | 
            ||
| 640 | |||
| 641 | /**  | 
            ||
| 642 | * Set the latest revision  | 
            ||
| 643 | * @param Revision $revision  | 
            ||
| 644 | */  | 
            ||
| 645 | 	protected function setLastEdit( Revision $revision ) { | 
            ||
| 649 | |||
| 650 | /**  | 
            ||
| 651 | * Get the latest revision  | 
            ||
| 652 | * @return Revision|null  | 
            ||
| 653 | */  | 
            ||
| 654 | 	public function getRevision() { | 
            ||
| 661 | |||
| 662 | /**  | 
            ||
| 663 | * Get the content of the current revision. No side-effects...  | 
            ||
| 664 | *  | 
            ||
| 665 | * @param int $audience One of:  | 
            ||
| 666 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 667 | * Revision::FOR_THIS_USER to be displayed to $wgUser  | 
            ||
| 668 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 669 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 670 | * to the $audience parameter  | 
            ||
| 671 | * @return Content|null The content of the current revision  | 
            ||
| 672 | *  | 
            ||
| 673 | * @since 1.21  | 
            ||
| 674 | */  | 
            ||
| 675 | View Code Duplication | 	public function getContent( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            |
| 682 | |||
| 683 | /**  | 
            ||
| 684 | * Get the text of the current revision. No side-effects...  | 
            ||
| 685 | *  | 
            ||
| 686 | * @param int $audience One of:  | 
            ||
| 687 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 688 | * Revision::FOR_THIS_USER to be displayed to the given user  | 
            ||
| 689 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 690 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 691 | * to the $audience parameter  | 
            ||
| 692 | * @return string|bool The text of the current revision  | 
            ||
| 693 | * @deprecated since 1.21, getContent() should be used instead.  | 
            ||
| 694 | */  | 
            ||
| 695 | 	public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            ||
| 704 | |||
| 705 | /**  | 
            ||
| 706 | * @return string MW timestamp of last article revision  | 
            ||
| 707 | */  | 
            ||
| 708 | 	public function getTimestamp() { | 
            ||
| 716 | |||
| 717 | /**  | 
            ||
| 718 | * Set the page timestamp (use only to avoid DB queries)  | 
            ||
| 719 | * @param string $ts MW timestamp of last article revision  | 
            ||
| 720 | * @return void  | 
            ||
| 721 | */  | 
            ||
| 722 | 	public function setTimestamp( $ts ) { | 
            ||
| 725 | |||
| 726 | /**  | 
            ||
| 727 | * @param int $audience One of:  | 
            ||
| 728 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 729 | * Revision::FOR_THIS_USER to be displayed to the given user  | 
            ||
| 730 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 731 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 732 | * to the $audience parameter  | 
            ||
| 733 | * @return int User ID for the user that made the last article revision  | 
            ||
| 734 | */  | 
            ||
| 735 | View Code Duplication | 	public function getUser( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            |
| 743 | |||
| 744 | /**  | 
            ||
| 745 | * Get the User object of the user who created the page  | 
            ||
| 746 | * @param int $audience One of:  | 
            ||
| 747 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 748 | * Revision::FOR_THIS_USER to be displayed to the given user  | 
            ||
| 749 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 750 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 751 | * to the $audience parameter  | 
            ||
| 752 | * @return User|null  | 
            ||
| 753 | */  | 
            ||
| 754 | 	public function getCreator( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            ||
| 763 | |||
| 764 | /**  | 
            ||
| 765 | * @param int $audience One of:  | 
            ||
| 766 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 767 | * Revision::FOR_THIS_USER to be displayed to the given user  | 
            ||
| 768 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 769 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 770 | * to the $audience parameter  | 
            ||
| 771 | * @return string Username of the user that made the last article revision  | 
            ||
| 772 | */  | 
            ||
| 773 | View Code Duplication | 	public function getUserText( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            |
| 781 | |||
| 782 | /**  | 
            ||
| 783 | * @param int $audience One of:  | 
            ||
| 784 | * Revision::FOR_PUBLIC to be displayed to all users  | 
            ||
| 785 | * Revision::FOR_THIS_USER to be displayed to the given user  | 
            ||
| 786 | * Revision::RAW get the text regardless of permissions  | 
            ||
| 787 | * @param User $user User object to check for, only if FOR_THIS_USER is passed  | 
            ||
| 788 | * to the $audience parameter  | 
            ||
| 789 | * @return string Comment stored for the last article revision  | 
            ||
| 790 | */  | 
            ||
| 791 | View Code Duplication | 	public function getComment( $audience = Revision::FOR_PUBLIC, User $user = null ) { | 
            |
| 799 | |||
| 800 | /**  | 
            ||
| 801 | * Returns true if last revision was marked as "minor edit"  | 
            ||
| 802 | *  | 
            ||
| 803 | * @return bool Minor edit indicator for the last article revision.  | 
            ||
| 804 | */  | 
            ||
| 805 | 	public function getMinorEdit() { | 
            ||
| 813 | |||
| 814 | /**  | 
            ||
| 815 | * Determine whether a page would be suitable for being counted as an  | 
            ||
| 816 | * article in the site_stats table based on the title & its content  | 
            ||
| 817 | *  | 
            ||
| 818 | * @param object|bool $editInfo (false): object returned by prepareTextForEdit(),  | 
            ||
| 819 | * if false, the current database state will be used  | 
            ||
| 820 | * @return bool  | 
            ||
| 821 | */  | 
            ||
| 822 | 	public function isCountable( $editInfo = false ) { | 
            ||
| 858 | |||
| 859 | /**  | 
            ||
| 860 | * If this page is a redirect, get its target  | 
            ||
| 861 | *  | 
            ||
| 862 | * The target will be fetched from the redirect table if possible.  | 
            ||
| 863 | * If this page doesn't have an entry there, call insertRedirect()  | 
            ||
| 864 | * @return Title|null Title object, or null if this page is not a redirect  | 
            ||
| 865 | */  | 
            ||
| 866 | 	public function getRedirectTarget() { | 
            ||
| 896 | |||
| 897 | /**  | 
            ||
| 898 | * Insert an entry for this page into the redirect table if the content is a redirect  | 
            ||
| 899 | *  | 
            ||
| 900 | * The database update will be deferred via DeferredUpdates  | 
            ||
| 901 | *  | 
            ||
| 902 | * Don't call this function directly unless you know what you're doing.  | 
            ||
| 903 | * @return Title|null Title object or null if not a redirect  | 
            ||
| 904 | */  | 
            ||
| 905 | 	public function insertRedirect() { | 
            ||
| 925 | |||
| 926 | /**  | 
            ||
| 927 | * Insert or update the redirect table entry for this page to indicate it redirects to $rt  | 
            ||
| 928 | * @param Title $rt Redirect target  | 
            ||
| 929 | * @param int|null $oldLatest Prior page_latest for check and set  | 
            ||
| 930 | */  | 
            ||
| 931 | 	public function insertRedirectEntry( Title $rt, $oldLatest = null ) { | 
            ||
| 951 | |||
| 952 | /**  | 
            ||
| 953 | * Get the Title object or URL this page redirects to  | 
            ||
| 954 | *  | 
            ||
| 955 | * @return bool|Title|string False, Title of in-wiki target, or string with URL  | 
            ||
| 956 | */  | 
            ||
| 957 | 	public function followRedirect() { | 
            ||
| 960 | |||
| 961 | /**  | 
            ||
| 962 | * Get the Title object or URL to use for a redirect. We use Title  | 
            ||
| 963 | * objects for same-wiki, non-special redirects and URLs for everything  | 
            ||
| 964 | * else.  | 
            ||
| 965 | * @param Title $rt Redirect target  | 
            ||
| 966 | * @return bool|Title|string False, Title object of local target, or string with URL  | 
            ||
| 967 | */  | 
            ||
| 968 | 	public function getRedirectURL( $rt ) { | 
            ||
| 1000 | |||
| 1001 | /**  | 
            ||
| 1002 | * Get a list of users who have edited this article, not including the user who made  | 
            ||
| 1003 | * the most recent revision, which you can get from $article->getUser() if you want it  | 
            ||
| 1004 | * @return UserArrayFromResult  | 
            ||
| 1005 | */  | 
            ||
| 1006 | 	public function getContributors() { | 
            ||
| 1052 | |||
| 1053 | /**  | 
            ||
| 1054 | * Should the parser cache be used?  | 
            ||
| 1055 | *  | 
            ||
| 1056 | * @param ParserOptions $parserOptions ParserOptions to check  | 
            ||
| 1057 | * @param int $oldId  | 
            ||
| 1058 | * @return bool  | 
            ||
| 1059 | */  | 
            ||
| 1060 | 	public function shouldCheckParserCache( ParserOptions $parserOptions, $oldId ) { | 
            ||
| 1066 | |||
| 1067 | /**  | 
            ||
| 1068 | * Get a ParserOutput for the given ParserOptions and revision ID.  | 
            ||
| 1069 | *  | 
            ||
| 1070 | * The parser cache will be used if possible. Cache misses that result  | 
            ||
| 1071 | * in parser runs are debounced with PoolCounter.  | 
            ||
| 1072 | *  | 
            ||
| 1073 | * @since 1.19  | 
            ||
| 1074 | * @param ParserOptions $parserOptions ParserOptions to use for the parse operation  | 
            ||
| 1075 | * @param null|int $oldid Revision ID to get the text from, passing null or 0 will  | 
            ||
| 1076 | * get the current revision (default value)  | 
            ||
| 1077 | * @param bool $forceParse Force reindexing, regardless of cache settings  | 
            ||
| 1078 | * @return bool|ParserOutput ParserOutput or false if the revision was not found  | 
            ||
| 1079 | */  | 
            ||
| 1080 | public function getParserOutput(  | 
            ||
| 1107 | |||
| 1108 | /**  | 
            ||
| 1109 | * Do standard deferred updates after page view (existing or missing page)  | 
            ||
| 1110 | * @param User $user The relevant user  | 
            ||
| 1111 | * @param int $oldid Revision id being viewed; if not given or 0, latest revision is assumed  | 
            ||
| 1112 | */  | 
            ||
| 1113 | 	public function doViewUpdates( User $user, $oldid = 0 ) { | 
            ||
| 1127 | |||
| 1128 | /**  | 
            ||
| 1129 | * Perform the actions of a page purging  | 
            ||
| 1130 | * @param integer $flags Bitfield of WikiPage::PURGE_* constants  | 
            ||
| 1131 | * @return bool  | 
            ||
| 1132 | */  | 
            ||
| 1133 | 	public function doPurge( $flags = self::PURGE_ALL ) { | 
            ||
| 1184 | |||
| 1185 | /**  | 
            ||
| 1186 | * Get the last time a user explicitly purged the page via action=purge  | 
            ||
| 1187 | *  | 
            ||
| 1188 | * @return string|bool TS_MW timestamp or false  | 
            ||
| 1189 | * @since 1.28  | 
            ||
| 1190 | */  | 
            ||
| 1191 | 	public function getLastPurgeTimestamp() { | 
            ||
| 1196 | |||
| 1197 | /**  | 
            ||
| 1198 | * Insert a new empty page record for this article.  | 
            ||
| 1199 | * This *must* be followed up by creating a revision  | 
            ||
| 1200 | * and running $this->updateRevisionOn( ... );  | 
            ||
| 1201 | * or else the record will be left in a funky state.  | 
            ||
| 1202 | * Best if all done inside a transaction.  | 
            ||
| 1203 | *  | 
            ||
| 1204 | * @param IDatabase $dbw  | 
            ||
| 1205 | * @param int|null $pageId Custom page ID that will be used for the insert statement  | 
            ||
| 1206 | *  | 
            ||
| 1207 | * @return bool|int The newly created page_id key; false if the row was not  | 
            ||
| 1208 | * inserted, e.g. because the title already existed or because the specified  | 
            ||
| 1209 | * page ID is already in use.  | 
            ||
| 1210 | */  | 
            ||
| 1211 | 	public function insertOn( $dbw, $pageId = null ) { | 
            ||
| 1241 | |||
| 1242 | /**  | 
            ||
| 1243 | * Update the page record to point to a newly saved revision.  | 
            ||
| 1244 | *  | 
            ||
| 1245 | * @param IDatabase $dbw  | 
            ||
| 1246 | * @param Revision $revision For ID number, and text used to set  | 
            ||
| 1247 | * length and redirect status fields  | 
            ||
| 1248 | * @param int $lastRevision If given, will not overwrite the page field  | 
            ||
| 1249 | * when different from the currently set value.  | 
            ||
| 1250 | * Giving 0 indicates the new page flag should be set on.  | 
            ||
| 1251 | * @param bool $lastRevIsRedirect If given, will optimize adding and  | 
            ||
| 1252 | * removing rows in redirect table.  | 
            ||
| 1253 | * @return bool Success; false if the page row was missing or page_latest changed  | 
            ||
| 1254 | */  | 
            ||
| 1255 | public function updateRevisionOn( $dbw, $revision, $lastRevision = null,  | 
            ||
| 1314 | |||
| 1315 | /**  | 
            ||
| 1316 | * Add row to the redirect table if this is a redirect, remove otherwise.  | 
            ||
| 1317 | *  | 
            ||
| 1318 | * @param IDatabase $dbw  | 
            ||
| 1319 | * @param Title $redirectTitle Title object pointing to the redirect target,  | 
            ||
| 1320 | * or NULL if this is not a redirect  | 
            ||
| 1321 | * @param null|bool $lastRevIsRedirect If given, will optimize adding and  | 
            ||
| 1322 | * removing rows in redirect table.  | 
            ||
| 1323 | * @return bool True on success, false on failure  | 
            ||
| 1324 | * @private  | 
            ||
| 1325 | */  | 
            ||
| 1326 | 	public function updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null ) { | 
            ||
| 1350 | |||
| 1351 | /**  | 
            ||
| 1352 | * If the given revision is newer than the currently set page_latest,  | 
            ||
| 1353 | * update the page record. Otherwise, do nothing.  | 
            ||
| 1354 | *  | 
            ||
| 1355 | * @deprecated since 1.24, use updateRevisionOn instead  | 
            ||
| 1356 | *  | 
            ||
| 1357 | * @param IDatabase $dbw  | 
            ||
| 1358 | * @param Revision $revision  | 
            ||
| 1359 | * @return bool  | 
            ||
| 1360 | */  | 
            ||
| 1361 | 	public function updateIfNewerOn( $dbw, $revision ) { | 
            ||
| 1387 | |||
| 1388 | /**  | 
            ||
| 1389 | * Get the content that needs to be saved in order to undo all revisions  | 
            ||
| 1390 | * between $undo and $undoafter. Revisions must belong to the same page,  | 
            ||
| 1391 | * must exist and must not be deleted  | 
            ||
| 1392 | * @param Revision $undo  | 
            ||
| 1393 | * @param Revision $undoafter Must be an earlier revision than $undo  | 
            ||
| 1394 | * @return Content|bool Content on success, false on failure  | 
            ||
| 1395 | * @since 1.21  | 
            ||
| 1396 | * Before we had the Content object, this was done in getUndoText  | 
            ||
| 1397 | */  | 
            ||
| 1398 | 	public function getUndoContent( Revision $undo, Revision $undoafter = null ) { | 
            ||
| 1402 | |||
| 1403 | /**  | 
            ||
| 1404 | * Returns true if this page's content model supports sections.  | 
            ||
| 1405 | *  | 
            ||
| 1406 | * @return bool  | 
            ||
| 1407 | *  | 
            ||
| 1408 | * @todo The skin should check this and not offer section functionality if  | 
            ||
| 1409 | * sections are not supported.  | 
            ||
| 1410 | * @todo The EditPage should check this and not offer section functionality  | 
            ||
| 1411 | * if sections are not supported.  | 
            ||
| 1412 | */  | 
            ||
| 1413 | 	public function supportsSections() { | 
            ||
| 1416 | |||
| 1417 | /**  | 
            ||
| 1418 | * @param string|number|null|bool $sectionId Section identifier as a number or string  | 
            ||
| 1419 | * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page  | 
            ||
| 1420 | * or 'new' for a new section.  | 
            ||
| 1421 | * @param Content $sectionContent New content of the section.  | 
            ||
| 1422 | * @param string $sectionTitle New section's subject, only if $section is "new".  | 
            ||
| 1423 | * @param string $edittime Revision timestamp or null to use the current revision.  | 
            ||
| 1424 | *  | 
            ||
| 1425 | * @throws MWException  | 
            ||
| 1426 | * @return Content|null New complete article content, or null if error.  | 
            ||
| 1427 | *  | 
            ||
| 1428 | * @since 1.21  | 
            ||
| 1429 | * @deprecated since 1.24, use replaceSectionAtRev instead  | 
            ||
| 1430 | */  | 
            ||
| 1431 | public function replaceSectionContent(  | 
            ||
| 1456 | |||
| 1457 | /**  | 
            ||
| 1458 | * @param string|number|null|bool $sectionId Section identifier as a number or string  | 
            ||
| 1459 | * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page  | 
            ||
| 1460 | * or 'new' for a new section.  | 
            ||
| 1461 | * @param Content $sectionContent New content of the section.  | 
            ||
| 1462 | * @param string $sectionTitle New section's subject, only if $section is "new".  | 
            ||
| 1463 | * @param int|null $baseRevId  | 
            ||
| 1464 | *  | 
            ||
| 1465 | * @throws MWException  | 
            ||
| 1466 | * @return Content|null New complete article content, or null if error.  | 
            ||
| 1467 | *  | 
            ||
| 1468 | * @since 1.24  | 
            ||
| 1469 | */  | 
            ||
| 1470 | public function replaceSectionAtRev( $sectionId, Content $sectionContent,  | 
            ||
| 1507 | |||
| 1508 | /**  | 
            ||
| 1509 | * Check flags and add EDIT_NEW or EDIT_UPDATE to them as needed.  | 
            ||
| 1510 | * @param int $flags  | 
            ||
| 1511 | * @return int Updated $flags  | 
            ||
| 1512 | */  | 
            ||
| 1513 | 	public function checkFlags( $flags ) { | 
            ||
| 1524 | |||
| 1525 | /**  | 
            ||
| 1526 | * Change an existing article or create a new article. Updates RC and all necessary caches,  | 
            ||
| 1527 | * optionally via the deferred update array.  | 
            ||
| 1528 | *  | 
            ||
| 1529 | * @param string $text New text  | 
            ||
| 1530 | * @param string $summary Edit summary  | 
            ||
| 1531 | * @param int $flags Bitfield:  | 
            ||
| 1532 | * EDIT_NEW  | 
            ||
| 1533 | * Article is known or assumed to be non-existent, create a new one  | 
            ||
| 1534 | * EDIT_UPDATE  | 
            ||
| 1535 | * Article is known or assumed to be pre-existing, update it  | 
            ||
| 1536 | * EDIT_MINOR  | 
            ||
| 1537 | * Mark this edit minor, if the user is allowed to do so  | 
            ||
| 1538 | * EDIT_SUPPRESS_RC  | 
            ||
| 1539 | * Do not log the change in recentchanges  | 
            ||
| 1540 | * EDIT_FORCE_BOT  | 
            ||
| 1541 | * Mark the edit a "bot" edit regardless of user rights  | 
            ||
| 1542 | * EDIT_AUTOSUMMARY  | 
            ||
| 1543 | * Fill in blank summaries with generated text where possible  | 
            ||
| 1544 | * EDIT_INTERNAL  | 
            ||
| 1545 | * Signal that the page retrieve/save cycle happened entirely in this request.  | 
            ||
| 1546 | *  | 
            ||
| 1547 | * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the  | 
            ||
| 1548 | * article will be detected. If EDIT_UPDATE is specified and the article  | 
            ||
| 1549 | * doesn't exist, the function will return an edit-gone-missing error. If  | 
            ||
| 1550 | * EDIT_NEW is specified and the article does exist, an edit-already-exists  | 
            ||
| 1551 | * error will be returned. These two conditions are also possible with  | 
            ||
| 1552 | * auto-detection due to MediaWiki's performance-optimised locking strategy.  | 
            ||
| 1553 | *  | 
            ||
| 1554 | * @param bool|int $baseRevId The revision ID this edit was based off, if any.  | 
            ||
| 1555 | * This is not the parent revision ID, rather the revision ID for older  | 
            ||
| 1556 | * content used as the source for a rollback, for example.  | 
            ||
| 1557 | * @param User $user The user doing the edit  | 
            ||
| 1558 | *  | 
            ||
| 1559 | * @throws MWException  | 
            ||
| 1560 | * @return Status Possible errors:  | 
            ||
| 1561 | * edit-hook-aborted: The ArticleSave hook aborted the edit but didn't  | 
            ||
| 1562 | * set the fatal flag of $status  | 
            ||
| 1563 | * edit-gone-missing: In update mode, but the article didn't exist.  | 
            ||
| 1564 | * edit-conflict: In update mode, the article changed unexpectedly.  | 
            ||
| 1565 | * edit-no-change: Warning that the text was the same as before.  | 
            ||
| 1566 | * edit-already-exists: In creation mode, but the article already exists.  | 
            ||
| 1567 | *  | 
            ||
| 1568 | * Extensions may define additional errors.  | 
            ||
| 1569 | *  | 
            ||
| 1570 | * $return->value will contain an associative array with members as follows:  | 
            ||
| 1571 | * new: Boolean indicating if the function attempted to create a new article.  | 
            ||
| 1572 | * revision: The revision object for the inserted revision, or null.  | 
            ||
| 1573 | *  | 
            ||
| 1574 | * Compatibility note: this function previously returned a boolean value  | 
            ||
| 1575 | * indicating success/failure  | 
            ||
| 1576 | *  | 
            ||
| 1577 | * @deprecated since 1.21: use doEditContent() instead.  | 
            ||
| 1578 | */  | 
            ||
| 1579 | 	public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) { | 
            ||
| 1586 | |||
| 1587 | /**  | 
            ||
| 1588 | * Change an existing article or create a new article. Updates RC and all necessary caches,  | 
            ||
| 1589 | * optionally via the deferred update array.  | 
            ||
| 1590 | *  | 
            ||
| 1591 | * @param Content $content New content  | 
            ||
| 1592 | * @param string $summary Edit summary  | 
            ||
| 1593 | * @param int $flags Bitfield:  | 
            ||
| 1594 | * EDIT_NEW  | 
            ||
| 1595 | * Article is known or assumed to be non-existent, create a new one  | 
            ||
| 1596 | * EDIT_UPDATE  | 
            ||
| 1597 | * Article is known or assumed to be pre-existing, update it  | 
            ||
| 1598 | * EDIT_MINOR  | 
            ||
| 1599 | * Mark this edit minor, if the user is allowed to do so  | 
            ||
| 1600 | * EDIT_SUPPRESS_RC  | 
            ||
| 1601 | * Do not log the change in recentchanges  | 
            ||
| 1602 | * EDIT_FORCE_BOT  | 
            ||
| 1603 | * Mark the edit a "bot" edit regardless of user rights  | 
            ||
| 1604 | * EDIT_AUTOSUMMARY  | 
            ||
| 1605 | * Fill in blank summaries with generated text where possible  | 
            ||
| 1606 | * EDIT_INTERNAL  | 
            ||
| 1607 | * Signal that the page retrieve/save cycle happened entirely in this request.  | 
            ||
| 1608 | *  | 
            ||
| 1609 | * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the  | 
            ||
| 1610 | * article will be detected. If EDIT_UPDATE is specified and the article  | 
            ||
| 1611 | * doesn't exist, the function will return an edit-gone-missing error. If  | 
            ||
| 1612 | * EDIT_NEW is specified and the article does exist, an edit-already-exists  | 
            ||
| 1613 | * error will be returned. These two conditions are also possible with  | 
            ||
| 1614 | * auto-detection due to MediaWiki's performance-optimised locking strategy.  | 
            ||
| 1615 | *  | 
            ||
| 1616 | * @param bool|int $baseRevId The revision ID this edit was based off, if any.  | 
            ||
| 1617 | * This is not the parent revision ID, rather the revision ID for older  | 
            ||
| 1618 | * content used as the source for a rollback, for example.  | 
            ||
| 1619 | * @param User $user The user doing the edit  | 
            ||
| 1620 | * @param string $serialFormat Format for storing the content in the  | 
            ||
| 1621 | * database.  | 
            ||
| 1622 | * @param array|null $tags Change tags to apply to this edit  | 
            ||
| 1623 | * Callers are responsible for permission checks  | 
            ||
| 1624 | * (with ChangeTags::canAddTagsAccompanyingChange)  | 
            ||
| 1625 | *  | 
            ||
| 1626 | * @throws MWException  | 
            ||
| 1627 | * @return Status Possible errors:  | 
            ||
| 1628 | * edit-hook-aborted: The ArticleSave hook aborted the edit but didn't  | 
            ||
| 1629 | * set the fatal flag of $status.  | 
            ||
| 1630 | * edit-gone-missing: In update mode, but the article didn't exist.  | 
            ||
| 1631 | * edit-conflict: In update mode, the article changed unexpectedly.  | 
            ||
| 1632 | * edit-no-change: Warning that the text was the same as before.  | 
            ||
| 1633 | * edit-already-exists: In creation mode, but the article already exists.  | 
            ||
| 1634 | *  | 
            ||
| 1635 | * Extensions may define additional errors.  | 
            ||
| 1636 | *  | 
            ||
| 1637 | * $return->value will contain an associative array with members as follows:  | 
            ||
| 1638 | * new: Boolean indicating if the function attempted to create a new article.  | 
            ||
| 1639 | * revision: The revision object for the inserted revision, or null.  | 
            ||
| 1640 | *  | 
            ||
| 1641 | * @since 1.21  | 
            ||
| 1642 | * @throws MWException  | 
            ||
| 1643 | */  | 
            ||
| 1644 | public function doEditContent(  | 
            ||
| 1743 | |||
| 1744 | /**  | 
            ||
| 1745 | * @param Content $content Pre-save transform content  | 
            ||
| 1746 | * @param integer $flags  | 
            ||
| 1747 | * @param User $user  | 
            ||
| 1748 | * @param string $summary  | 
            ||
| 1749 | * @param array $meta  | 
            ||
| 1750 | * @return Status  | 
            ||
| 1751 | * @throws DBUnexpectedError  | 
            ||
| 1752 | * @throws Exception  | 
            ||
| 1753 | * @throws FatalError  | 
            ||
| 1754 | * @throws MWException  | 
            ||
| 1755 | */  | 
            ||
| 1756 | private function doModify(  | 
            ||
| 1915 | |||
| 1916 | /**  | 
            ||
| 1917 | * @param Content $content Pre-save transform content  | 
            ||
| 1918 | * @param integer $flags  | 
            ||
| 1919 | * @param User $user  | 
            ||
| 1920 | * @param string $summary  | 
            ||
| 1921 | * @param array $meta  | 
            ||
| 1922 | * @return Status  | 
            ||
| 1923 | * @throws DBUnexpectedError  | 
            ||
| 1924 | * @throws Exception  | 
            ||
| 1925 | * @throws FatalError  | 
            ||
| 1926 | * @throws MWException  | 
            ||
| 1927 | */  | 
            ||
| 1928 | private function doCreate(  | 
            ||
| 2040 | |||
| 2041 | /**  | 
            ||
| 2042 | * Get parser options suitable for rendering the primary article wikitext  | 
            ||
| 2043 | *  | 
            ||
| 2044 | * @see ContentHandler::makeParserOptions  | 
            ||
| 2045 | *  | 
            ||
| 2046 | * @param IContextSource|User|string $context One of the following:  | 
            ||
| 2047 | * - IContextSource: Use the User and the Language of the provided  | 
            ||
| 2048 | * context  | 
            ||
| 2049 | * - User: Use the provided User object and $wgLang for the language,  | 
            ||
| 2050 | * so use an IContextSource object if possible.  | 
            ||
| 2051 | * - 'canonical': Canonical options (anonymous user with default  | 
            ||
| 2052 | * preferences and content language).  | 
            ||
| 2053 | * @return ParserOptions  | 
            ||
| 2054 | */  | 
            ||
| 2055 | 	public function makeParserOptions( $context ) { | 
            ||
| 2066 | |||
| 2067 | /**  | 
            ||
| 2068 | * Prepare text which is about to be saved.  | 
            ||
| 2069 | * Returns a stdClass with source, pst and output members  | 
            ||
| 2070 | *  | 
            ||
| 2071 | * @param string $text  | 
            ||
| 2072 | * @param int|null $revid  | 
            ||
| 2073 | * @param User|null $user  | 
            ||
| 2074 | * @deprecated since 1.21: use prepareContentForEdit instead.  | 
            ||
| 2075 | * @return object  | 
            ||
| 2076 | */  | 
            ||
| 2077 | 	public function prepareTextForEdit( $text, $revid = null, User $user = null ) { | 
            ||
| 2082 | |||
| 2083 | /**  | 
            ||
| 2084 | * Prepare content which is about to be saved.  | 
            ||
| 2085 | * Returns a stdClass with source, pst and output members  | 
            ||
| 2086 | *  | 
            ||
| 2087 | * @param Content $content  | 
            ||
| 2088 | * @param Revision|int|null $revision Revision object. For backwards compatibility, a  | 
            ||
| 2089 | * revision ID is also accepted, but this is deprecated.  | 
            ||
| 2090 | * @param User|null $user  | 
            ||
| 2091 | * @param string|null $serialFormat  | 
            ||
| 2092 | * @param bool $useCache Check shared prepared edit cache  | 
            ||
| 2093 | *  | 
            ||
| 2094 | * @return object  | 
            ||
| 2095 | *  | 
            ||
| 2096 | * @since 1.21  | 
            ||
| 2097 | */  | 
            ||
| 2098 | public function prepareContentForEdit(  | 
            ||
| 2218 | |||
| 2219 | /**  | 
            ||
| 2220 | * Do standard deferred updates after page edit.  | 
            ||
| 2221 | * Update links tables, site stats, search index and message cache.  | 
            ||
| 2222 | * Purges pages that include this page if the text was changed here.  | 
            ||
| 2223 | * Every 100th edit, prune the recent changes table.  | 
            ||
| 2224 | *  | 
            ||
| 2225 | * @param Revision $revision  | 
            ||
| 2226 | * @param User $user User object that did the revision  | 
            ||
| 2227 | * @param array $options Array of options, following indexes are used:  | 
            ||
| 2228 | * - changed: boolean, whether the revision changed the content (default true)  | 
            ||
| 2229 | * - created: boolean, whether the revision created the page (default false)  | 
            ||
| 2230 | * - moved: boolean, whether the page was moved (default false)  | 
            ||
| 2231 | * - restored: boolean, whether the page was undeleted (default false)  | 
            ||
| 2232 | * - oldrevision: Revision object for the pre-update revision (default null)  | 
            ||
| 2233 | * - oldcountable: boolean, null, or string 'no-change' (default null):  | 
            ||
| 2234 | * - boolean: whether the page was counted as an article before that  | 
            ||
| 2235 | * revision, only used in changed is true and created is false  | 
            ||
| 2236 | * - null: if created is false, don't update the article count; if created  | 
            ||
| 2237 | * is true, do update the article count  | 
            ||
| 2238 | * - 'no-change': don't update the article count, ever  | 
            ||
| 2239 | */  | 
            ||
| 2240 | 	public function doEditUpdates( Revision $revision, User $user, array $options = [] ) { | 
            ||
| 2398 | |||
| 2399 | /**  | 
            ||
| 2400 | * Edit an article without doing all that other stuff  | 
            ||
| 2401 | * The article must already exist; link tables etc  | 
            ||
| 2402 | * are not updated, caches are not flushed.  | 
            ||
| 2403 | *  | 
            ||
| 2404 | * @param Content $content Content submitted  | 
            ||
| 2405 | * @param User $user The relevant user  | 
            ||
| 2406 | * @param string $comment Comment submitted  | 
            ||
| 2407 | * @param bool $minor Whereas it's a minor modification  | 
            ||
| 2408 | * @param string $serialFormat Format for storing the content in the database  | 
            ||
| 2409 | */  | 
            ||
| 2410 | public function doQuickEditContent(  | 
            ||
| 2433 | |||
| 2434 | /**  | 
            ||
| 2435 | * Update the article's restriction field, and leave a log entry.  | 
            ||
| 2436 | * This works for protection both existing and non-existing pages.  | 
            ||
| 2437 | *  | 
            ||
| 2438 | * @param array $limit Set of restriction keys  | 
            ||
| 2439 | * @param array $expiry Per restriction type expiration  | 
            ||
| 2440 | * @param int &$cascade Set to false if cascading protection isn't allowed.  | 
            ||
| 2441 | * @param string $reason  | 
            ||
| 2442 | * @param User $user The user updating the restrictions  | 
            ||
| 2443 | * @param string|string[] $tags Change tags to add to the pages and protection log entries  | 
            ||
| 2444 | * ($user should be able to add the specified tags before this is called)  | 
            ||
| 2445 | * @return Status Status object; if action is taken, $status->value is the log_id of the  | 
            ||
| 2446 | * protection log entry.  | 
            ||
| 2447 | */  | 
            ||
| 2448 | public function doUpdateRestrictions( array $limit, array $expiry,  | 
            ||
| 2689 | |||
| 2690 | /**  | 
            ||
| 2691 | * Insert a new null revision for this page.  | 
            ||
| 2692 | *  | 
            ||
| 2693 | * @param string $revCommentMsg Comment message key for the revision  | 
            ||
| 2694 | * @param array $limit Set of restriction keys  | 
            ||
| 2695 | * @param array $expiry Per restriction type expiration  | 
            ||
| 2696 | * @param int $cascade Set to false if cascading protection isn't allowed.  | 
            ||
| 2697 | * @param string $reason  | 
            ||
| 2698 | * @param User|null $user  | 
            ||
| 2699 | * @return Revision|null Null on error  | 
            ||
| 2700 | */  | 
            ||
| 2701 | public function insertProtectNullRevision( $revCommentMsg, array $limit,  | 
            ||
| 2741 | |||
| 2742 | /**  | 
            ||
| 2743 | * @param string $expiry 14-char timestamp or "infinity", or false if the input was invalid  | 
            ||
| 2744 | * @return string  | 
            ||
| 2745 | */  | 
            ||
| 2746 | 	protected function formatExpiry( $expiry ) { | 
            ||
| 2761 | |||
| 2762 | /**  | 
            ||
| 2763 | * Builds the description to serve as comment for the edit.  | 
            ||
| 2764 | *  | 
            ||
| 2765 | * @param array $limit Set of restriction keys  | 
            ||
| 2766 | * @param array $expiry Per restriction type expiration  | 
            ||
| 2767 | * @return string  | 
            ||
| 2768 | */  | 
            ||
| 2769 | 	public function protectDescription( array $limit, array $expiry ) { | 
            ||
| 2799 | |||
| 2800 | /**  | 
            ||
| 2801 | * Builds the description to serve as comment for the log entry.  | 
            ||
| 2802 | *  | 
            ||
| 2803 | * Some bots may parse IRC lines, which are generated from log entries which contain plain  | 
            ||
| 2804 | * protect description text. Keep them in old format to avoid breaking compatibility.  | 
            ||
| 2805 | * TODO: Fix protection log to store structured description and format it on-the-fly.  | 
            ||
| 2806 | *  | 
            ||
| 2807 | * @param array $limit Set of restriction keys  | 
            ||
| 2808 | * @param array $expiry Per restriction type expiration  | 
            ||
| 2809 | * @return string  | 
            ||
| 2810 | */  | 
            ||
| 2811 | 	public function protectDescriptionLog( array $limit, array $expiry ) { | 
            ||
| 2824 | |||
| 2825 | /**  | 
            ||
| 2826 | * Take an array of page restrictions and flatten it to a string  | 
            ||
| 2827 | * suitable for insertion into the page_restrictions field.  | 
            ||
| 2828 | *  | 
            ||
| 2829 | * @param string[] $limit  | 
            ||
| 2830 | *  | 
            ||
| 2831 | * @throws MWException  | 
            ||
| 2832 | * @return string  | 
            ||
| 2833 | */  | 
            ||
| 2834 | 	protected static function flattenRestrictions( $limit ) { | 
            ||
| 2848 | |||
| 2849 | /**  | 
            ||
| 2850 | * Same as doDeleteArticleReal(), but returns a simple boolean. This is kept around for  | 
            ||
| 2851 | * backwards compatibility, if you care about error reporting you should use  | 
            ||
| 2852 | * doDeleteArticleReal() instead.  | 
            ||
| 2853 | *  | 
            ||
| 2854 | * Deletes the article with database consistency, writes logs, purges caches  | 
            ||
| 2855 | *  | 
            ||
| 2856 | * @param string $reason Delete reason for deletion log  | 
            ||
| 2857 | * @param bool $suppress Suppress all revisions and log the deletion in  | 
            ||
| 2858 | * the suppression log instead of the deletion log  | 
            ||
| 2859 | * @param int $u1 Unused  | 
            ||
| 2860 | * @param bool $u2 Unused  | 
            ||
| 2861 | * @param array|string &$error Array of errors to append to  | 
            ||
| 2862 | * @param User $user The deleting user  | 
            ||
| 2863 | * @return bool True if successful  | 
            ||
| 2864 | */  | 
            ||
| 2865 | public function doDeleteArticle(  | 
            ||
| 2871 | |||
| 2872 | /**  | 
            ||
| 2873 | * Back-end article deletion  | 
            ||
| 2874 | * Deletes the article with database consistency, writes logs, purges caches  | 
            ||
| 2875 | *  | 
            ||
| 2876 | * @since 1.19  | 
            ||
| 2877 | *  | 
            ||
| 2878 | * @param string $reason Delete reason for deletion log  | 
            ||
| 2879 | * @param bool $suppress Suppress all revisions and log the deletion in  | 
            ||
| 2880 | * the suppression log instead of the deletion log  | 
            ||
| 2881 | * @param int $u1 Unused  | 
            ||
| 2882 | * @param bool $u2 Unused  | 
            ||
| 2883 | * @param array|string &$error Array of errors to append to  | 
            ||
| 2884 | * @param User $user The deleting user  | 
            ||
| 2885 | * @return Status Status object; if successful, $status->value is the log_id of the  | 
            ||
| 2886 | * deletion log entry. If the page couldn't be deleted because it wasn't  | 
            ||
| 2887 | * found, $status is a non-fatal 'cannotdelete' error  | 
            ||
| 2888 | */  | 
            ||
| 2889 | public function doDeleteArticleReal(  | 
            ||
| 2890 | $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null  | 
            ||
| 2891 | 	) { | 
            ||
| 2892 | global $wgUser, $wgContentHandlerUseDB;  | 
            ||
| 2893 | |||
| 2894 | wfDebug( __METHOD__ . "\n" );  | 
            ||
| 2895 | |||
| 2896 | $status = Status::newGood();  | 
            ||
| 2897 | |||
| 2898 | 		if ( $this->mTitle->getDBkey() === '' ) { | 
            ||
| 2899 | $status->error( 'cannotdelete',  | 
            ||
| 2900 | wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );  | 
            ||
| 2901 | return $status;  | 
            ||
| 2902 | }  | 
            ||
| 2903 | |||
| 2904 | $user = is_null( $user ) ? $wgUser : $user;  | 
            ||
| 2905 | if ( !Hooks::run( 'ArticleDelete',  | 
            ||
| 2906 | [ &$this, &$user, &$reason, &$error, &$status, $suppress ]  | 
            ||
| 2907 | 		) ) { | 
            ||
| 2908 | 			if ( $status->isOK() ) { | 
            ||
| 2909 | // Hook aborted but didn't set a fatal status  | 
            ||
| 2910 | $status->fatal( 'delete-hook-aborted' );  | 
            ||
| 2911 | }  | 
            ||
| 2912 | return $status;  | 
            ||
| 2913 | }  | 
            ||
| 2914 | |||
| 2915 | $dbw = wfGetDB( DB_MASTER );  | 
            ||
| 2916 | $dbw->startAtomic( __METHOD__ );  | 
            ||
| 2917 | |||
| 2918 | $this->loadPageData( self::READ_LATEST );  | 
            ||
| 2919 | $id = $this->getId();  | 
            ||
| 2920 | // T98706: lock the page from various other updates but avoid using  | 
            ||
| 2921 | // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to  | 
            ||
| 2922 | // the revisions queries (which also JOIN on user). Only lock the page  | 
            ||
| 2923 | // row and CAS check on page_latest to see if the trx snapshot matches.  | 
            ||
| 2924 | $lockedLatest = $this->lockAndGetLatest();  | 
            ||
| 2925 | 		if ( $id == 0 || $this->getLatest() != $lockedLatest ) { | 
            ||
| 2926 | $dbw->endAtomic( __METHOD__ );  | 
            ||
| 2927 | // Page not there or trx snapshot is stale  | 
            ||
| 2928 | $status->error( 'cannotdelete',  | 
            ||
| 2929 | wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );  | 
            ||
| 2930 | return $status;  | 
            ||
| 2931 | }  | 
            ||
| 2932 | |||
| 2933 | // Given the lock above, we can be confident in the title and page ID values  | 
            ||
| 2934 | $namespace = $this->getTitle()->getNamespace();  | 
            ||
| 2935 | $dbKey = $this->getTitle()->getDBkey();  | 
            ||
| 2936 | |||
| 2937 | // At this point we are now comitted to returning an OK  | 
            ||
| 2938 | // status unless some DB query error or other exception comes up.  | 
            ||
| 2939 | // This way callers don't have to call rollback() if $status is bad  | 
            ||
| 2940 | // unless they actually try to catch exceptions (which is rare).  | 
            ||
| 2941 | |||
| 2942 | // we need to remember the old content so we can use it to generate all deletion updates.  | 
            ||
| 2943 | 		try { | 
            ||
| 2944 | $content = $this->getContent( Revision::RAW );  | 
            ||
| 2945 | 		} catch ( Exception $ex ) { | 
            ||
| 2946 | wfLogWarning( __METHOD__ . ': failed to load content during deletion! '  | 
            ||
| 2947 | . $ex->getMessage() );  | 
            ||
| 2948 | |||
| 2949 | $content = null;  | 
            ||
| 2950 | }  | 
            ||
| 2951 | |||
| 2952 | // Bitfields to further suppress the content  | 
            ||
| 2953 | 		if ( $suppress ) { | 
            ||
| 2954 | $bitfield = 0;  | 
            ||
| 2955 | // This should be 15...  | 
            ||
| 2956 | $bitfield |= Revision::DELETED_TEXT;  | 
            ||
| 2957 | $bitfield |= Revision::DELETED_COMMENT;  | 
            ||
| 2958 | $bitfield |= Revision::DELETED_USER;  | 
            ||
| 2959 | $bitfield |= Revision::DELETED_RESTRICTED;  | 
            ||
| 2960 | $deletionFields = [ $dbw->addQuotes( $bitfield ) . ' AS deleted' ];  | 
            ||
| 2961 | 		} else { | 
            ||
| 2962 | $deletionFields = [ 'rev_deleted AS deleted' ];  | 
            ||
| 2963 | }  | 
            ||
| 2964 | |||
| 2965 | // For now, shunt the revision data into the archive table.  | 
            ||
| 2966 | // Text is *not* removed from the text table; bulk storage  | 
            ||
| 2967 | // is left intact to avoid breaking block-compression or  | 
            ||
| 2968 | // immutable storage schemes.  | 
            ||
| 2969 | // In the future, we may keep revisions and mark them with  | 
            ||
| 2970 | // the rev_deleted field, which is reserved for this purpose.  | 
            ||
| 2971 | |||
| 2972 | // Get all of the page revisions  | 
            ||
| 2973 | $fields = array_diff( Revision::selectFields(), [ 'rev_deleted' ] );  | 
            ||
| 2974 | $res = $dbw->select(  | 
            ||
| 2975 | 'revision',  | 
            ||
| 2976 | array_merge( $fields, $deletionFields ),  | 
            ||
| 2977 | [ 'rev_page' => $id ],  | 
            ||
| 2978 | __METHOD__,  | 
            ||
| 2979 | 'FOR UPDATE'  | 
            ||
| 2980 | );  | 
            ||
| 2981 | // Build their equivalent archive rows  | 
            ||
| 2982 | $rowsInsert = [];  | 
            ||
| 2983 | 		foreach ( $res as $row ) { | 
            ||
| 2984 | $rowInsert = [  | 
            ||
| 2985 | 'ar_namespace' => $namespace,  | 
            ||
| 2986 | 'ar_title' => $dbKey,  | 
            ||
| 2987 | 'ar_comment' => $row->rev_comment,  | 
            ||
| 2988 | 'ar_user' => $row->rev_user,  | 
            ||
| 2989 | 'ar_user_text' => $row->rev_user_text,  | 
            ||
| 2990 | 'ar_timestamp' => $row->rev_timestamp,  | 
            ||
| 2991 | 'ar_minor_edit' => $row->rev_minor_edit,  | 
            ||
| 2992 | 'ar_rev_id' => $row->rev_id,  | 
            ||
| 2993 | 'ar_parent_id' => $row->rev_parent_id,  | 
            ||
| 2994 | 'ar_text_id' => $row->rev_text_id,  | 
            ||
| 2995 | 'ar_text' => '',  | 
            ||
| 2996 | 'ar_flags' => '',  | 
            ||
| 2997 | 'ar_len' => $row->rev_len,  | 
            ||
| 2998 | 'ar_page_id' => $id,  | 
            ||
| 2999 | 'ar_deleted' => $row->deleted,  | 
            ||
| 3000 | 'ar_sha1' => $row->rev_sha1,  | 
            ||
| 3001 | ];  | 
            ||
| 3002 | 			if ( $wgContentHandlerUseDB ) { | 
            ||
| 3003 | $rowInsert['ar_content_model'] = $row->rev_content_model;  | 
            ||
| 3004 | $rowInsert['ar_content_format'] = $row->rev_content_format;  | 
            ||
| 3005 | }  | 
            ||
| 3006 | $rowsInsert[] = $rowInsert;  | 
            ||
| 3007 | }  | 
            ||
| 3008 | // Copy them into the archive table  | 
            ||
| 3009 | $dbw->insert( 'archive', $rowsInsert, __METHOD__ );  | 
            ||
| 3010 | // Save this so we can pass it to the ArticleDeleteComplete hook.  | 
            ||
| 3011 | $archivedRevisionCount = $dbw->affectedRows();  | 
            ||
| 3012 | |||
| 3013 | // Clone the title and wikiPage, so we have the information we need when  | 
            ||
| 3014 | // we log and run the ArticleDeleteComplete hook.  | 
            ||
| 3015 | $logTitle = clone $this->mTitle;  | 
            ||
| 3016 | $wikiPageBeforeDelete = clone $this;  | 
            ||
| 3017 | |||
| 3018 | // Now that it's safely backed up, delete it  | 
            ||
| 3019 | $dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );  | 
            ||
| 3020 | $dbw->delete( 'revision', [ 'rev_page' => $id ], __METHOD__ );  | 
            ||
| 3021 | |||
| 3022 | // Log the deletion, if the page was suppressed, put it in the suppression log instead  | 
            ||
| 3023 | $logtype = $suppress ? 'suppress' : 'delete';  | 
            ||
| 3024 | |||
| 3025 | $logEntry = new ManualLogEntry( $logtype, 'delete' );  | 
            ||
| 3026 | $logEntry->setPerformer( $user );  | 
            ||
| 3027 | $logEntry->setTarget( $logTitle );  | 
            ||
| 3028 | $logEntry->setComment( $reason );  | 
            ||
| 3029 | $logid = $logEntry->insert();  | 
            ||
| 3030 | |||
| 3031 | $dbw->onTransactionPreCommitOrIdle(  | 
            ||
| 3032 | 			function () use ( $dbw, $logEntry, $logid ) { | 
            ||
| 3033 | // Bug 56776: avoid deadlocks (especially from FileDeleteForm)  | 
            ||
| 3034 | $logEntry->publish( $logid );  | 
            ||
| 3035 | },  | 
            ||
| 3036 | __METHOD__  | 
            ||
| 3037 | );  | 
            ||
| 3038 | |||
| 3039 | $dbw->endAtomic( __METHOD__ );  | 
            ||
| 3040 | |||
| 3041 | $this->doDeleteUpdates( $id, $content );  | 
            ||
| 3042 | |||
| 3043 | Hooks::run( 'ArticleDeleteComplete', [  | 
            ||
| 3044 | &$wikiPageBeforeDelete,  | 
            ||
| 3045 | &$user,  | 
            ||
| 3046 | $reason,  | 
            ||
| 3047 | $id,  | 
            ||
| 3048 | $content,  | 
            ||
| 3049 | $logEntry,  | 
            ||
| 3050 | $archivedRevisionCount  | 
            ||
| 3051 | ] );  | 
            ||
| 3052 | $status->value = $logid;  | 
            ||
| 3053 | |||
| 3054 | // Show log excerpt on 404 pages rather than just a link  | 
            ||
| 3055 | $cache = ObjectCache::getMainStashInstance();  | 
            ||
| 3056 | $key = wfMemcKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );  | 
            ||
| 3057 | $cache->set( $key, 1, $cache::TTL_DAY );  | 
            ||
| 3058 | |||
| 3059 | return $status;  | 
            ||
| 3060 | }  | 
            ||
| 3061 | |||
| 3062 | /**  | 
            ||
| 3063 | * Lock the page row for this title+id and return page_latest (or 0)  | 
            ||
| 3064 | *  | 
            ||
| 3065 | * @return integer Returns 0 if no row was found with this title+id  | 
            ||
| 3066 | * @since 1.27  | 
            ||
| 3067 | */  | 
            ||
| 3068 | 	public function lockAndGetLatest() { | 
            ||
| 3083 | |||
| 3084 | /**  | 
            ||
| 3085 | * Do some database updates after deletion  | 
            ||
| 3086 | *  | 
            ||
| 3087 | * @param int $id The page_id value of the page being deleted  | 
            ||
| 3088 | * @param Content $content Optional page content to be used when determining  | 
            ||
| 3089 | * the required updates. This may be needed because $this->getContent()  | 
            ||
| 3090 | * may already return null when the page proper was deleted.  | 
            ||
| 3091 | */  | 
            ||
| 3092 | 	public function doDeleteUpdates( $id, Content $content = null ) { | 
            ||
| 3127 | |||
| 3128 | /**  | 
            ||
| 3129 | * Roll back the most recent consecutive set of edits to a page  | 
            ||
| 3130 | * from the same user; fails if there are no eligible edits to  | 
            ||
| 3131 | * roll back to, e.g. user is the sole contributor. This function  | 
            ||
| 3132 | * performs permissions checks on $user, then calls commitRollback()  | 
            ||
| 3133 | * to do the dirty work  | 
            ||
| 3134 | *  | 
            ||
| 3135 | * @todo Separate the business/permission stuff out from backend code  | 
            ||
| 3136 | * @todo Remove $token parameter. Already verified by RollbackAction and ApiRollback.  | 
            ||
| 3137 | *  | 
            ||
| 3138 | * @param string $fromP Name of the user whose edits to rollback.  | 
            ||
| 3139 | * @param string $summary Custom summary. Set to default summary if empty.  | 
            ||
| 3140 | * @param string $token Rollback token.  | 
            ||
| 3141 | * @param bool $bot If true, mark all reverted edits as bot.  | 
            ||
| 3142 | *  | 
            ||
| 3143 | * @param array $resultDetails Array contains result-specific array of additional values  | 
            ||
| 3144 | * 'alreadyrolled' : 'current' (rev)  | 
            ||
| 3145 | * success : 'summary' (str), 'current' (rev), 'target' (rev)  | 
            ||
| 3146 | *  | 
            ||
| 3147 | * @param User $user The user performing the rollback  | 
            ||
| 3148 | * @param array|null $tags Change tags to apply to the rollback  | 
            ||
| 3149 | * Callers are responsible for permission checks  | 
            ||
| 3150 | * (with ChangeTags::canAddTagsAccompanyingChange)  | 
            ||
| 3151 | *  | 
            ||
| 3152 | * @return array Array of errors, each error formatted as  | 
            ||
| 3153 | * array(messagekey, param1, param2, ...).  | 
            ||
| 3154 | * On success, the array is empty. This array can also be passed to  | 
            ||
| 3155 | * OutputPage::showPermissionsErrorPage().  | 
            ||
| 3156 | */  | 
            ||
| 3157 | public function doRollback(  | 
            ||
| 3182 | |||
| 3183 | /**  | 
            ||
| 3184 | * Backend implementation of doRollback(), please refer there for parameter  | 
            ||
| 3185 | * and return value documentation  | 
            ||
| 3186 | *  | 
            ||
| 3187 | * NOTE: This function does NOT check ANY permissions, it just commits the  | 
            ||
| 3188 | * rollback to the DB. Therefore, you should only call this function direct-  | 
            ||
| 3189 | * ly if you want to use custom permissions checks. If you don't, use  | 
            ||
| 3190 | * doRollback() instead.  | 
            ||
| 3191 | * @param string $fromP Name of the user whose edits to rollback.  | 
            ||
| 3192 | * @param string $summary Custom summary. Set to default summary if empty.  | 
            ||
| 3193 | * @param bool $bot If true, mark all reverted edits as bot.  | 
            ||
| 3194 | *  | 
            ||
| 3195 | * @param array $resultDetails Contains result-specific array of additional values  | 
            ||
| 3196 | * @param User $guser The user performing the rollback  | 
            ||
| 3197 | * @param array|null $tags Change tags to apply to the rollback  | 
            ||
| 3198 | * Callers are responsible for permission checks  | 
            ||
| 3199 | * (with ChangeTags::canAddTagsAccompanyingChange)  | 
            ||
| 3200 | *  | 
            ||
| 3201 | * @return array  | 
            ||
| 3202 | */  | 
            ||
| 3203 | public function commitRollback( $fromP, $summary, $bot,  | 
            ||
| 3378 | |||
| 3379 | /**  | 
            ||
| 3380 | * The onArticle*() functions are supposed to be a kind of hooks  | 
            ||
| 3381 | * which should be called whenever any of the specified actions  | 
            ||
| 3382 | * are done.  | 
            ||
| 3383 | *  | 
            ||
| 3384 | * This is a good place to put code to clear caches, for instance.  | 
            ||
| 3385 | *  | 
            ||
| 3386 | * This is called on page move and undelete, as well as edit  | 
            ||
| 3387 | *  | 
            ||
| 3388 | * @param Title $title  | 
            ||
| 3389 | */  | 
            ||
| 3390 | 	public static function onArticleCreate( Title $title ) { | 
            ||
| 3410 | |||
| 3411 | /**  | 
            ||
| 3412 | * Clears caches when article is deleted  | 
            ||
| 3413 | *  | 
            ||
| 3414 | * @param Title $title  | 
            ||
| 3415 | */  | 
            ||
| 3416 | 	public static function onArticleDelete( Title $title ) { | 
            ||
| 3458 | |||
| 3459 | /**  | 
            ||
| 3460 | * Purge caches on page update etc  | 
            ||
| 3461 | *  | 
            ||
| 3462 | * @param Title $title  | 
            ||
| 3463 | * @param Revision|null $revision Revision that was just saved, may be null  | 
            ||
| 3464 | */  | 
            ||
| 3465 | 	public static function onArticleEdit( Title $title, Revision $revision = null ) { | 
            ||
| 3484 | |||
| 3485 | /**#@-*/  | 
            ||
| 3486 | |||
| 3487 | /**  | 
            ||
| 3488 | * Returns a list of categories this page is a member of.  | 
            ||
| 3489 | * Results will include hidden categories  | 
            ||
| 3490 | *  | 
            ||
| 3491 | * @return TitleArray  | 
            ||
| 3492 | */  | 
            ||
| 3493 | 	public function getCategories() { | 
            ||
| 3509 | |||
| 3510 | /**  | 
            ||
| 3511 | * Returns a list of hidden categories this page is a member of.  | 
            ||
| 3512 | * Uses the page_props and categorylinks tables.  | 
            ||
| 3513 | *  | 
            ||
| 3514 | * @return array Array of Title objects  | 
            ||
| 3515 | */  | 
            ||
| 3516 | 	public function getHiddenCategories() { | 
            ||
| 3539 | |||
| 3540 | /**  | 
            ||
| 3541 | * Return an applicable autosummary if one exists for the given edit.  | 
            ||
| 3542 | * @param string|null $oldtext The previous text of the page.  | 
            ||
| 3543 | * @param string|null $newtext The submitted text of the page.  | 
            ||
| 3544 | * @param int $flags Bitmask: a bitmask of flags submitted for the edit.  | 
            ||
| 3545 | * @return string An appropriate autosummary, or an empty string.  | 
            ||
| 3546 | *  | 
            ||
| 3547 | * @deprecated since 1.21, use ContentHandler::getAutosummary() instead  | 
            ||
| 3548 | */  | 
            ||
| 3549 | 	public static function getAutosummary( $oldtext, $newtext, $flags ) { | 
            ||
| 3561 | |||
| 3562 | /**  | 
            ||
| 3563 | * Auto-generates a deletion reason  | 
            ||
| 3564 | *  | 
            ||
| 3565 | * @param bool &$hasHistory Whether the page has a history  | 
            ||
| 3566 | * @return string|bool String containing deletion reason or empty string, or boolean false  | 
            ||
| 3567 | * if no revision occurred  | 
            ||
| 3568 | */  | 
            ||
| 3569 | 	public function getAutoDeleteReason( &$hasHistory ) { | 
            ||
| 3572 | |||
| 3573 | /**  | 
            ||
| 3574 | * Update all the appropriate counts in the category table, given that  | 
            ||
| 3575 | * we've added the categories $added and deleted the categories $deleted.  | 
            ||
| 3576 | *  | 
            ||
| 3577 | * @param array $added The names of categories that were added  | 
            ||
| 3578 | * @param array $deleted The names of categories that were deleted  | 
            ||
| 3579 | * @param integer $id Page ID (this should be the original deleted page ID)  | 
            ||
| 3580 | */  | 
            ||
| 3581 | 	public function updateCategoryCounts( array $added, array $deleted, $id = 0 ) { | 
            ||
| 3679 | |||
| 3680 | /**  | 
            ||
| 3681 | * Opportunistically enqueue link update jobs given fresh parser output if useful  | 
            ||
| 3682 | *  | 
            ||
| 3683 | * @param ParserOutput $parserOutput Current version page output  | 
            ||
| 3684 | * @since 1.25  | 
            ||
| 3685 | */  | 
            ||
| 3686 | 	public function triggerOpportunisticLinksUpdate( ParserOutput $parserOutput ) { | 
            ||
| 3730 | |||
| 3731 | /**  | 
            ||
| 3732 | * Returns a list of updates to be performed when this page is deleted. The  | 
            ||
| 3733 | * updates should remove any information about this page from secondary data  | 
            ||
| 3734 | * stores such as links tables.  | 
            ||
| 3735 | *  | 
            ||
| 3736 | * @param Content|null $content Optional Content object for determining the  | 
            ||
| 3737 | * necessary updates.  | 
            ||
| 3738 | * @return DeferrableUpdate[]  | 
            ||
| 3739 | */  | 
            ||
| 3740 | 	public function getDeletionUpdates( Content $content = null ) { | 
            ||
| 3763 | |||
| 3764 | /**  | 
            ||
| 3765 | * Whether this content displayed on this page  | 
            ||
| 3766 | * comes from the local database  | 
            ||
| 3767 | *  | 
            ||
| 3768 | * @since 1.28  | 
            ||
| 3769 | * @return bool  | 
            ||
| 3770 | */  | 
            ||
| 3771 | 	public function isLocal() { | 
            ||
| 3774 | }  | 
            ||
| 3775 | 
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.