X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Fpage%2FWikiPage.php;h=dd78d198529c4a7dd8c55a558ad105244d206dbb;hp=928fc14ecb31b36a20baa4618be7cb36e29a8e5e;hb=939199bcea28a3b13c49c0f808d11d415660b924;hpb=7c6d2a0fa28746b49d79345b609d9c7605ed4d63 diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 928fc14ecb..dd78d19852 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -121,6 +121,11 @@ class WikiPage implements Page, IDBAccessObject { throw new MWException( "Invalid or virtual namespace $ns given." ); } + $page = null; + if ( !Hooks::run( 'WikiPageFactory', [ $title, &$page ] ) ) { + return $page; + } + switch ( $ns ) { case NS_FILE: $page = new WikiFilePage( $title ); @@ -693,7 +698,7 @@ class WikiPage implements Page, IDBAccessObject { * @deprecated since 1.21, getContent() should be used instead. */ public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) { - ContentHandler::deprecated( __METHOD__, '1.21' ); + wfDeprecated( __METHOD__, '1.21' ); $this->loadLastEdit(); if ( $this->mLastRevision ) { @@ -1678,7 +1683,7 @@ class WikiPage implements Page, IDBAccessObject { $flags & EDIT_MINOR, null, null, &$flags, &$hookStatus ]; // Check if the hook rejected the attempted save if ( !Hooks::run( 'PageContentSave', $hook_args ) - || !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args ) + || !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args, '1.21' ) ) { if ( $hookStatus->isOK() ) { // Hook returned false but didn't call fatal(); use generic message @@ -2023,11 +2028,11 @@ class WikiPage implements Page, IDBAccessObject { // Trigger post-create hook $params = [ &$this, &$user, $content, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision ]; - ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $params ); + ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $params, '1.21' ); Hooks::run( 'PageContentInsertComplete', $params ); // Trigger post-save hook $params = array_merge( $params, [ &$status, $meta['baseRevId'] ] ); - ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $params ); + ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $params, '1.21' ); Hooks::run( 'PageContentSaveComplete', $params ); } @@ -2075,7 +2080,7 @@ class WikiPage implements Page, IDBAccessObject { * @return object */ public function prepareTextForEdit( $text, $revid = null, User $user = null ) { - ContentHandler::deprecated( __METHOD__, '1.21' ); + wfDeprecated( __METHOD__, '1.21' ); $content = ContentHandler::makeContent( $text, $this->getTitle() ); return $this->prepareContentForEdit( $content, $revid, $user ); } @@ -2394,41 +2399,10 @@ class WikiPage implements Page, IDBAccessObject { } elseif ( $options['changed'] ) { // bug 50785 self::onArticleEdit( $this->mTitle, $revision ); } - } - - /** - * Edit an article without doing all that other stuff - * The article must already exist; link tables etc - * are not updated, caches are not flushed. - * - * @param Content $content Content submitted - * @param User $user The relevant user - * @param string $comment Comment submitted - * @param bool $minor Whereas it's a minor modification - * @param string $serialFormat Format for storing the content in the database - */ - public function doQuickEditContent( - Content $content, User $user, $comment = '', $minor = false, $serialFormat = null - ) { - - $serialized = $content->serialize( $serialFormat ); - - $dbw = wfGetDB( DB_MASTER ); - $revision = new Revision( [ - 'title' => $this->getTitle(), // for determining the default content model - 'page' => $this->getId(), - 'user_text' => $user->getName(), - 'user' => $user->getId(), - 'text' => $serialized, - 'length' => $content->getSize(), - 'comment' => $comment, - 'minor_edit' => $minor ? 1 : 0, - ] ); // XXX: set the content object? - $revision->insertOn( $dbw ); - $this->updateRevisionOn( $dbw, $revision ); - - Hooks::run( 'NewRevisionFromEditComplete', [ $this, $revision, false, $user ] ); + ResourceLoaderWikiModule::invalidateModuleCache( + $this->mTitle, $options['oldrevision'], $revision, wfWikiID() + ); } /** @@ -2511,13 +2485,13 @@ class WikiPage implements Page, IDBAccessObject { } if ( !$protect ) { // No protection at all means unprotection - $revCommentMsg = 'unprotectedarticle'; + $revCommentMsg = 'unprotectedarticle-comment'; $logAction = 'unprotect'; } elseif ( $isProtected ) { - $revCommentMsg = 'modifiedarticleprotection'; + $revCommentMsg = 'modifiedarticleprotection-comment'; $logAction = 'modify'; } else { - $revCommentMsg = 'protectedarticle'; + $revCommentMsg = 'protectedarticle-comment'; $logAction = 'protect'; } @@ -2701,16 +2675,14 @@ class WikiPage implements Page, IDBAccessObject { public function insertProtectNullRevision( $revCommentMsg, array $limit, array $expiry, $cascade, $reason, $user = null ) { - global $wgContLang; $dbw = wfGetDB( DB_MASTER ); // Prepare a null revision to be added to the history - $editComment = $wgContLang->ucfirst( - wfMessage( - $revCommentMsg, - $this->mTitle->getPrefixedText() - )->inContentLanguage()->text() - ); + $editComment = wfMessage( + $revCommentMsg, + $this->mTitle->getPrefixedText(), + $user ? $user->getName() : '' + )->inContentLanguage()->text(); if ( $reason ) { $editComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason; } @@ -2942,6 +2914,7 @@ class WikiPage implements Page, IDBAccessObject { // unless they actually try to catch exceptions (which is rare). // we need to remember the old content so we can use it to generate all deletion updates. + $revision = $this->getRevision(); try { $content = $this->getContent( Revision::RAW ); } catch ( Exception $ex ) { @@ -2951,17 +2924,13 @@ class WikiPage implements Page, IDBAccessObject { $content = null; } + $fields = Revision::selectFields(); + $bitfield = false; + // Bitfields to further suppress the content if ( $suppress ) { - $bitfield = 0; - // This should be 15... - $bitfield |= Revision::DELETED_TEXT; - $bitfield |= Revision::DELETED_COMMENT; - $bitfield |= Revision::DELETED_USER; - $bitfield |= Revision::DELETED_RESTRICTED; - $deletionFields = [ $dbw->addQuotes( $bitfield ) . ' AS deleted' ]; - } else { - $deletionFields = [ 'rev_deleted AS deleted' ]; + $bitfield = Revision::SUPPRESSED_ALL; + $fields = array_diff( $fields, [ 'rev_deleted' ] ); } // For now, shunt the revision data into the archive table. @@ -2972,10 +2941,9 @@ class WikiPage implements Page, IDBAccessObject { // the rev_deleted field, which is reserved for this purpose. // Get all of the page revisions - $fields = array_diff( Revision::selectFields(), [ 'rev_deleted' ] ); $res = $dbw->select( 'revision', - array_merge( $fields, $deletionFields ), + $fields, [ 'rev_page' => $id ], __METHOD__, 'FOR UPDATE' @@ -2998,7 +2966,7 @@ class WikiPage implements Page, IDBAccessObject { 'ar_flags' => '', 'ar_len' => $row->rev_len, 'ar_page_id' => $id, - 'ar_deleted' => $row->deleted, + 'ar_deleted' => $suppress ? $bitfield : $row->rev_deleted, 'ar_sha1' => $row->rev_sha1, ]; if ( $wgContentHandlerUseDB ) { @@ -3041,7 +3009,7 @@ class WikiPage implements Page, IDBAccessObject { $dbw->endAtomic( __METHOD__ ); - $this->doDeleteUpdates( $id, $content ); + $this->doDeleteUpdates( $id, $content, $revision ); Hooks::run( 'ArticleDeleteComplete', [ &$wikiPageBeforeDelete, @@ -3088,11 +3056,12 @@ class WikiPage implements Page, IDBAccessObject { * Do some database updates after deletion * * @param int $id The page_id value of the page being deleted - * @param Content $content Optional page content to be used when determining + * @param Content|null $content Optional page content to be used when determining * the required updates. This may be needed because $this->getContent() * may already return null when the page proper was deleted. + * @param Revision|null $revision The latest page revision */ - public function doDeleteUpdates( $id, Content $content = null ) { + public function doDeleteUpdates( $id, Content $content = null, Revision $revision = null ) { try { $countable = $this->isCountable(); } catch ( Exception $ex ) { @@ -3120,6 +3089,9 @@ class WikiPage implements Page, IDBAccessObject { // Clear caches WikiPage::onArticleDelete( $this->mTitle ); + ResourceLoaderWikiModule::invalidateModuleCache( + $this->mTitle, $revision, null, wfWikiID() + ); // Reset this object and the Title object $this->loadFromRow( false, self::READ_LATEST ); @@ -3577,107 +3549,103 @@ class WikiPage implements Page, IDBAccessObject { * Update all the appropriate counts in the category table, given that * we've added the categories $added and deleted the categories $deleted. * + * This should only be called from deferred updates or jobs to avoid contention. + * * @param array $added The names of categories that were added * @param array $deleted The names of categories that were deleted * @param integer $id Page ID (this should be the original deleted page ID) */ public function updateCategoryCounts( array $added, array $deleted, $id = 0 ) { $id = $id ?: $this->getId(); + $ns = $this->getTitle()->getNamespace(); + + $addFields = [ 'cat_pages = cat_pages + 1' ]; + $removeFields = [ 'cat_pages = cat_pages - 1' ]; + if ( $ns == NS_CATEGORY ) { + $addFields[] = 'cat_subcats = cat_subcats + 1'; + $removeFields[] = 'cat_subcats = cat_subcats - 1'; + } elseif ( $ns == NS_FILE ) { + $addFields[] = 'cat_files = cat_files + 1'; + $removeFields[] = 'cat_files = cat_files - 1'; + } + $dbw = wfGetDB( DB_MASTER ); - $method = __METHOD__; - // Do this at the end of the commit to reduce lock wait timeouts - $dbw->onTransactionPreCommitOrIdle( - function () use ( $dbw, $added, $deleted, $id, $method ) { - $ns = $this->getTitle()->getNamespace(); - - $addFields = [ 'cat_pages = cat_pages + 1' ]; - $removeFields = [ 'cat_pages = cat_pages - 1' ]; - if ( $ns == NS_CATEGORY ) { - $addFields[] = 'cat_subcats = cat_subcats + 1'; - $removeFields[] = 'cat_subcats = cat_subcats - 1'; - } elseif ( $ns == NS_FILE ) { - $addFields[] = 'cat_files = cat_files + 1'; - $removeFields[] = 'cat_files = cat_files - 1'; - } - if ( count( $added ) ) { - $existingAdded = $dbw->selectFieldValues( - 'category', - 'cat_title', - [ 'cat_title' => $added ], - $method - ); + if ( count( $added ) ) { + $existingAdded = $dbw->selectFieldValues( + 'category', + 'cat_title', + [ 'cat_title' => $added ], + __METHOD__ + ); - // For category rows that already exist, do a plain - // UPDATE instead of INSERT...ON DUPLICATE KEY UPDATE - // to avoid creating gaps in the cat_id sequence. - if ( count( $existingAdded ) ) { - $dbw->update( - 'category', - $addFields, - [ 'cat_title' => $existingAdded ], - $method - ); - } + // For category rows that already exist, do a plain + // UPDATE instead of INSERT...ON DUPLICATE KEY UPDATE + // to avoid creating gaps in the cat_id sequence. + if ( count( $existingAdded ) ) { + $dbw->update( + 'category', + $addFields, + [ 'cat_title' => $existingAdded ], + __METHOD__ + ); + } - $missingAdded = array_diff( $added, $existingAdded ); - if ( count( $missingAdded ) ) { - $insertRows = []; - foreach ( $missingAdded as $cat ) { - $insertRows[] = [ - 'cat_title' => $cat, - 'cat_pages' => 1, - 'cat_subcats' => ( $ns == NS_CATEGORY ) ? 1 : 0, - 'cat_files' => ( $ns == NS_FILE ) ? 1 : 0, - ]; - } - $dbw->upsert( - 'category', - $insertRows, - [ 'cat_title' ], - $addFields, - $method - ); - } + $missingAdded = array_diff( $added, $existingAdded ); + if ( count( $missingAdded ) ) { + $insertRows = []; + foreach ( $missingAdded as $cat ) { + $insertRows[] = [ + 'cat_title' => $cat, + 'cat_pages' => 1, + 'cat_subcats' => ( $ns == NS_CATEGORY ) ? 1 : 0, + 'cat_files' => ( $ns == NS_FILE ) ? 1 : 0, + ]; } + $dbw->upsert( + 'category', + $insertRows, + [ 'cat_title' ], + $addFields, + __METHOD__ + ); + } + } - if ( count( $deleted ) ) { - $dbw->update( - 'category', - $removeFields, - [ 'cat_title' => $deleted ], - $method - ); - } + if ( count( $deleted ) ) { + $dbw->update( + 'category', + $removeFields, + [ 'cat_title' => $deleted ], + __METHOD__ + ); + } - foreach ( $added as $catName ) { - $cat = Category::newFromName( $catName ); - Hooks::run( 'CategoryAfterPageAdded', [ $cat, $this ] ); - } + foreach ( $added as $catName ) { + $cat = Category::newFromName( $catName ); + Hooks::run( 'CategoryAfterPageAdded', [ $cat, $this ] ); + } - foreach ( $deleted as $catName ) { - $cat = Category::newFromName( $catName ); - Hooks::run( 'CategoryAfterPageRemoved', [ $cat, $this, $id ] ); - } + foreach ( $deleted as $catName ) { + $cat = Category::newFromName( $catName ); + Hooks::run( 'CategoryAfterPageRemoved', [ $cat, $this, $id ] ); + } - // Refresh counts on categories that should be empty now, to - // trigger possible deletion. Check master for the most - // up-to-date cat_pages. - if ( count( $deleted ) ) { - $rows = $dbw->select( - 'category', - [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ], - [ 'cat_title' => $deleted, 'cat_pages <= 0' ], - $method - ); - foreach ( $rows as $row ) { - $cat = Category::newFromRow( $row ); - $cat->refreshCounts(); - } - } - }, - __METHOD__ - ); + // Refresh counts on categories that should be empty now, to + // trigger possible deletion. Check master for the most + // up-to-date cat_pages. + if ( count( $deleted ) ) { + $rows = $dbw->select( + 'category', + [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ], + [ 'cat_title' => $deleted, 'cat_pages <= 0' ], + __METHOD__ + ); + foreach ( $rows as $row ) { + $cat = Category::newFromRow( $row ); + $cat->refreshCounts(); + } + } } /**