X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2FRevision.php;h=8849697e0fcc5b25454a44f4a68d2ec29e6e6872;hb=4589f4d78183fcfde2009e217ea8524102c95a31;hp=8f36e88fbea06079fa13b0d3bbcf482e2b3966f3;hpb=005857aba57362d415b9436f2341f5456b6a3567;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Revision.php b/includes/Revision.php index 8f36e88fbe..8849697e0f 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -65,7 +65,7 @@ class Revision implements IDBAccessObject { } /** - * @param bool|string $wikiId The ID of the target wiki database. Use false for the local wiki. + * @param bool|string $wiki The ID of the target wiki database. Use false for the local wiki. * * @return SqlBlobStore */ @@ -94,54 +94,11 @@ class Revision implements IDBAccessObject { * * @param int $id * @param int $flags (optional) - * @param Title $title (optional) If known you can pass the Title in here. - * Passing no Title may result in another DB query if there are recent writes. * @return Revision|null */ - public static function newFromId( $id, $flags = 0, Title $title = null ) { - /** - * MCR RevisionStore Compat - * - * If the title is not passed in as a param (already known) then select it here. - * - * Do the selection with MASTER if $flags includes READ_LATEST or recent changes - * have happened on our load balancer. - * - * If we select the title here and pass it down it will results in fewer queries - * further down the stack. - */ - if ( !$title ) { - if ( - $flags & self::READ_LATEST || - wfGetLB()->hasOrMadeRecentMasterChanges() - ) { - $dbr = wfGetDB( DB_MASTER ); - } else { - $dbr = wfGetDB( DB_REPLICA ); - } - $row = $dbr->selectRow( - [ 'revision', 'page' ], - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - ], - [ 'rev_id' => $id ], - __METHOD__, - [], - [ 'page' => [ 'JOIN', 'page_id=rev_page' ] ] - ); - if ( $row ) { - $title = Title::newFromRow( $row ); - } - wfGetLB()->reuseConnection( $dbr ); - } - - $rec = self::getRevisionStore()->getRevisionById( $id, $flags, $title ); - return $rec === null ? null : new Revision( $rec, $flags, $title ); + public static function newFromId( $id, $flags = 0 ) { + $rec = self::getRevisionStore()->getRevisionById( $id, $flags ); + return $rec === null ? null : new Revision( $rec, $flags ); } /** @@ -188,12 +145,11 @@ class Revision implements IDBAccessObject { * * @param object $row * @param array $overrides - * @param Title $title (optional) * * @throws MWException * @return Revision */ - public static function newFromArchiveRow( $row, $overrides = [], Title $title = null ) { + public static function newFromArchiveRow( $row, $overrides = [] ) { /** * MCR Migration: https://phabricator.wikimedia.org/T183564 * This method used to overwrite attributes, then passed to Revision::__construct @@ -205,6 +161,29 @@ class Revision implements IDBAccessObject { unset( $overrides['page'] ); } + /** + * We require a Title for both the Revision object and the RevisionRecord. + * Below is duplicated logic from RevisionStore::newRevisionFromArchiveRow + * to fetch a title in order pass it into the Revision object. + */ + $title = null; + if ( isset( $overrides['title'] ) ) { + if ( !( $overrides['title'] instanceof Title ) ) { + throw new MWException( 'title field override must contain a Title object.' ); + } + + $title = $overrides['title']; + } + if ( $title !== null ) { + if ( isset( $row->ar_namespace ) && isset( $row->ar_title ) ) { + $title = Title::makeTitle( $row->ar_namespace, $row->ar_title ); + } else { + throw new InvalidArgumentException( + 'A Title or ar_namespace and ar_title must be given' + ); + } + } + $rec = self::getRevisionStore()->newRevisionFromArchiveRow( $row, 0, $title, $overrides ); return new Revision( $rec, self::READ_NORMAL, $title ); } @@ -214,8 +193,9 @@ class Revision implements IDBAccessObject { * * MCR migration note: replaced by RevisionStore::newRevisionFromRow(). Note that * newFromRow() also accepts arrays, while newRevisionFromRow() does not. Instead, - * a MutableRevisionRecord should be constructed directly. RevisionStore::newRevisionFromArray() - * can be used as a temporary replacement, but should be avoided. + * a MutableRevisionRecord should be constructed directly. + * RevisionStore::newMutableRevisionFromArray() can be used as a temporary replacement, + * but should be avoided. * * @param object|array $row * @return Revision @@ -285,7 +265,8 @@ class Revision implements IDBAccessObject { * WARNING: Timestamps may in some circumstances not be unique, * so this isn't the best key to use. * - * @deprecated since 1.31, use RevisionStore::loadRevisionFromTimestamp() instead. + * @deprecated since 1.31, use RevisionStore::getRevisionByTimestamp() + * or RevisionStore::loadRevisionFromTimestamp() instead. * * @param IDatabase $db * @param Title $title @@ -293,7 +274,6 @@ class Revision implements IDBAccessObject { * @return Revision|null */ public static function loadFromTimestamp( $db, $title, $timestamp ) { - // XXX: replace loadRevisionFromTimestamp by getRevisionByTimestamp? $rec = self::getRevisionStore()->loadRevisionFromTimestamp( $db, $title, $timestamp ); return $rec === null ? null : new Revision( $rec ); } @@ -482,6 +462,9 @@ class Revision implements IDBAccessObject { /** * Do a batched query to get the parent revision lengths + * + * @deprecated in 1.31, use RevisionStore::getRevisionSizes instead. + * * @param IDatabase $db * @param array $revIds * @return array @@ -503,6 +486,8 @@ class Revision implements IDBAccessObject { if ( $row instanceof RevisionRecord ) { $this->mRecord = $row; } elseif ( is_array( $row ) ) { + // If no user is specified, fall back to using the global user object, to stay + // compatible with pre-1.31 behavior. if ( !isset( $row['user'] ) && !isset( $row['user_text'] ) ) { $row['user'] = $wgUser; } @@ -510,13 +495,13 @@ class Revision implements IDBAccessObject { $this->mRecord = self::getRevisionStore()->newMutableRevisionFromArray( $row, $queryFlags, - $title + $this->ensureTitle( $row, $queryFlags, $title ) ); } elseif ( is_object( $row ) ) { $this->mRecord = self::getRevisionStore()->newRevisionFromRow( $row, $queryFlags, - $title + $this->ensureTitle( $row, $queryFlags, $title ) ); } else { throw new InvalidArgumentException( @@ -525,6 +510,51 @@ class Revision implements IDBAccessObject { } } + /** + * Make sure we have *some* Title object for use by the constructor. + * For B/C, the constructor shouldn't fail even for a bad page ID or bad revision ID. + * + * @param array|object $row + * @param int $queryFlags + * @param Title|null $title + * + * @return Title $title if not null, or a Title constructed from information in $row. + */ + private function ensureTitle( $row, $queryFlags, $title = null ) { + if ( $title ) { + return $title; + } + + if ( is_array( $row ) ) { + if ( isset( $row['title'] ) ) { + if ( !( $row['title'] instanceof Title ) ) { + throw new MWException( 'title field must contain a Title object.' ); + } + + return $row['title']; + } + + $pageId = isset( $row['page'] ) ? $row['page'] : 0; + $revId = isset( $row['id'] ) ? $row['id'] : 0; + } else { + $pageId = isset( $row->rev_page ) ? $row->rev_page : 0; + $revId = isset( $row->rev_id ) ? $row->rev_id : 0; + } + + try { + $title = self::getRevisionStore()->getTitle( $pageId, $revId, $queryFlags ); + } catch ( RevisionAccessException $ex ) { + // construct a dummy title! + wfLogWarning( __METHOD__ . ': ' . $ex->getMessage() ); + + // NOTE: this Title will only be used inside RevisionRecord + $title = Title::makeTitleSafe( NS_SPECIAL, "Badtitle/ID=$pageId" ); + $title->resetArticleID( $pageId ); + } + + return $title; + } + /** * @return RevisionRecord */ @@ -794,7 +824,7 @@ class Revision implements IDBAccessObject { * @return int Rcid of the unpatrolled row, zero if there isn't one */ public function isUnpatrolled() { - return self::getRevisionStore()->isUnpatrolled( $this->mRecord ); + return self::getRevisionStore()->getRcIdIfUnpatrolled( $this->mRecord ); } /** @@ -938,10 +968,9 @@ class Revision implements IDBAccessObject { * @return Revision|null */ public function getPrevious() { - $rec = self::getRevisionStore()->getPreviousRevision( $this->mRecord, $this->getTitle() ); - return $rec === null - ? null - : new Revision( $rec, self::READ_NORMAL, $this->getTitle() ); + $title = $this->getTitle(); + $rec = self::getRevisionStore()->getPreviousRevision( $this->mRecord, $title ); + return $rec === null ? null : new Revision( $rec, self::READ_NORMAL, $title ); } /** @@ -950,10 +979,9 @@ class Revision implements IDBAccessObject { * @return Revision|null */ public function getNext() { - $rec = self::getRevisionStore()->getNextRevision( $this->mRecord, $this->getTitle() ); - return $rec === null - ? null - : new Revision( $rec, self::READ_NORMAL, $this->getTitle() ); + $title = $this->getTitle(); + $rec = self::getRevisionStore()->getNextRevision( $this->mRecord, $title ); + return $rec === null ? null : new Revision( $rec, self::READ_NORMAL, $title ); } /** @@ -1204,6 +1232,10 @@ class Revision implements IDBAccessObject { ? $pageIdOrTitle : Title::newFromID( $pageIdOrTitle ); + if ( !$title ) { + return false; + } + $record = self::getRevisionStore()->getKnownCurrentRevision( $title, $revId ); return $record ? new Revision( $record ) : false; }