Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
65.67% covered (warning)
65.67%
44 / 67
CRAP
78.99% covered (warning)
78.99%
218 / 276
Revision
0.00% covered (danger)
0.00%
0 / 1
65.67% covered (warning)
65.67%
44 / 67
332.77
78.99% covered (warning)
78.99%
218 / 276
 getRevisionStore
0.00% covered (danger)
0.00%
0 / 1
2.50
50.00% covered (danger)
50.00%
2 / 4
 getRevisionLookup
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getRevisionFactory
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getBlobStore
0.00% covered (danger)
0.00%
0 / 1
2.09
71.43% covered (warning)
71.43%
5 / 7
 newFromId
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 newFromTitle
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 newFromPageId
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 newFromArchiveRow
0.00% covered (danger)
0.00%
0 / 1
17.58
40.00% covered (danger)
40.00%
6 / 15
 newFromRow
0.00% covered (danger)
0.00%
0 / 1
2.06
75.00% covered (warning)
75.00%
3 / 4
 loadFromId
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 loadFromPageId
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 loadFromTitle
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 loadFromTimestamp
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 userJoinCond
0.00% covered (danger)
0.00%
0 / 1
2.15
66.67% covered (warning)
66.67%
4 / 6
 pageJoinCond
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 selectFields
0.00% covered (danger)
0.00%
0 / 1
4.30
73.33% covered (warning)
73.33%
11 / 15
 selectArchiveFields
0.00% covered (danger)
0.00%
0 / 1
4.30
73.33% covered (warning)
73.33%
11 / 15
 selectTextFields
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 selectPageFields
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 selectUserFields
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 getQueryInfo
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getArchiveQueryInfo
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getParentLengths
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
19 / 19
 ensureTitle
0.00% covered (danger)
0.00%
0 / 1
8.51
58.82% covered (warning)
58.82%
10 / 17
 getRevisionRecord
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getId
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 setId
0.00% covered (danger)
0.00%
0 / 1
2.06
75.00% covered (warning)
75.00%
3 / 4
 setUserIdAndName
0.00% covered (danger)
0.00%
0 / 1
2.03
80.00% covered (warning)
80.00%
4 / 5
 getMainSlotRaw
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getTextId
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 getParentId
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getSize
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 getSha1
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 getTitle
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 setTitle
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 getPage
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getUser
0.00% covered (danger)
0.00%
0 / 1
4.13
80.00% covered (warning)
80.00%
4 / 5
 getUserText
0.00% covered (danger)
0.00%
0 / 1
4.13
80.00% covered (warning)
80.00%
4 / 5
 getComment
0.00% covered (danger)
0.00%
0 / 1
4.13
80.00% covered (warning)
80.00%
4 / 5
 isMinor
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 isUnpatrolled
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getRecentChange
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 isDeleted
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getVisibility
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getContent
0.00% covered (danger)
0.00%
0 / 1
4.07
83.33% covered (warning)
83.33%
5 / 6
 getSerializedData
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 getContentModel
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getContentFormat
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 getContentHandler
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getTimestamp
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 isCurrent
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
1 / 1
 getPrevious
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 getNext
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 getRevisionText
0.00% covered (danger)
0.00%
0 / 1
11.73
81.82% covered (warning)
81.82%
27 / 33
 compressRevisionText
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 decompressRevisionText
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 insertOn
0.00% covered (danger)
0.00%
0 / 1
3.33
66.67% covered (warning)
66.67%
6 / 9
 base36Sha1
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 newNullRevision
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
9 / 9
 userCan
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 userCanBitfield
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 getTimestampFromId
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 countByPageId
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 countByTitle
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 userWasLastToEdit
0.00% covered (danger)
0.00%
0 / 1
2.15
66.67% covered (warning)
66.67%
2 / 3
 newKnownCurrent
0.00% covered (danger)
0.00%
0 / 1
4.05
85.71% covered (warning)
85.71%
6 / 7
<?php
/**
 * Representation of a page version.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @file
 */
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RevisionAccessException;
use MediaWiki\Revision\RevisionFactory;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\RevisionStoreRecord;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Storage\SqlBlobStore;
use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\IDatabase;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
/**
 * @deprecated since 1.31, use RevisionRecord, RevisionStore, and BlobStore instead.
 */
class Revision implements IDBAccessObject {
    /** @var RevisionRecord */
    protected $mRecord;
    // Revision deletion constants
    const DELETED_TEXT = RevisionRecord::DELETED_TEXT;
    const DELETED_COMMENT = RevisionRecord::DELETED_COMMENT;
    const DELETED_USER = RevisionRecord::DELETED_USER;
    const DELETED_RESTRICTED = RevisionRecord::DELETED_RESTRICTED;
    const SUPPRESSED_USER = RevisionRecord::SUPPRESSED_USER;
    const SUPPRESSED_ALL = RevisionRecord::SUPPRESSED_ALL;
    // Audience options for accessors
    const FOR_PUBLIC = RevisionRecord::FOR_PUBLIC;
    const FOR_THIS_USER = RevisionRecord::FOR_THIS_USER;
    const RAW = RevisionRecord::RAW;
    const TEXT_CACHE_GROUP = SqlBlobStore::TEXT_CACHE_GROUP;
    /**
     * @return RevisionStore
     */
    protected static function getRevisionStore( $wiki = false ) {
        if ( $wiki ) {
            return MediaWikiServices::getInstance()->getRevisionStoreFactory()
                ->getRevisionStore( $wiki );
        } else {
            return MediaWikiServices::getInstance()->getRevisionStore();
        }
    }
    /**
     * @return RevisionLookup
     */
    protected static function getRevisionLookup() {
        return MediaWikiServices::getInstance()->getRevisionLookup();
    }
    /**
     * @return RevisionFactory
     */
    protected static function getRevisionFactory() {
        return MediaWikiServices::getInstance()->getRevisionFactory();
    }
    /**
     * @param bool|string $wiki The ID of the target wiki database. Use false for the local wiki.
     *
     * @return SqlBlobStore
     */
    protected static function getBlobStore( $wiki = false ) {
        $store = MediaWikiServices::getInstance()
            ->getBlobStoreFactory()
            ->newSqlBlobStore( $wiki );
        if ( !$store instanceof SqlBlobStore ) {
            throw new RuntimeException(
                'The backwards compatibility code in Revision currently requires the BlobStore '
                . 'service to be an SqlBlobStore instance, but it is a ' . get_class( $store )
            );
        }
        return $store;
    }
    /**
     * Load a page revision from a given revision ID number.
     * Returns null if no such revision can be found.
     *
     * $flags include:
     *      Revision::READ_LATEST  : Select the data from the master
     *      Revision::READ_LOCKING : Select & lock the data from the master
     *
     * @param int $id
     * @param int $flags (optional)
     * @return Revision|null
     */
    public static function newFromId( $id, $flags = 0 ) {
        $rec = self::getRevisionLookup()->getRevisionById( $id, $flags );
        return $rec ? new Revision( $rec, $flags ) : null;
    }
    /**
     * Load either the current, or a specified, revision
     * that's attached to a given link target. If not attached
     * to that link target, will return null.
     *
     * $flags include:
     *      Revision::READ_LATEST  : Select the data from the master
     *      Revision::READ_LOCKING : Select & lock the data from the master
     *
     * @param LinkTarget $linkTarget
     * @param int $id (optional)
     * @param int $flags Bitfield (optional)
     * @return Revision|null
     */
    public static function newFromTitle( LinkTarget $linkTarget, $id = 0, $flags = 0 ) {
        $rec = self::getRevisionLookup()->getRevisionByTitle( $linkTarget, $id, $flags );
        return $rec ? new Revision( $rec, $flags ) : null;
    }
    /**
     * Load either the current, or a specified, revision
     * that's attached to a given page ID.
     * Returns null if no such revision can be found.
     *
     * $flags include:
     *      Revision::READ_LATEST  : Select the data from the master (since 1.20)
     *      Revision::READ_LOCKING : Select & lock the data from the master
     *
     * @param int $pageId
     * @param int $revId (optional)
     * @param int $flags Bitfield (optional)
     * @return Revision|null
     */
    public static function newFromPageId( $pageId, $revId = 0, $flags = 0 ) {
        $rec = self::getRevisionLookup()->getRevisionByPageId( $pageId, $revId, $flags );
        return $rec ? new Revision( $rec, $flags ) : null;
    }
    /**
     * Make a fake revision object from an archive table row. This is queried
     * for permissions or even inserted (as in Special:Undelete)
     *
     * @param object $row
     * @param array $overrides
     *
     * @throws MWException
     * @return Revision
     */
    public static function newFromArchiveRow( $row, $overrides = [] ) {
        /**
         * MCR Migration: https://phabricator.wikimedia.org/T183564
         * This method used to overwrite attributes, then passed to Revision::__construct
         * RevisionStore::newRevisionFromArchiveRow instead overrides row field names
         * So do a conversion here.
         */
        if ( array_key_exists( 'page', $overrides ) ) {
            $overrides['page_id'] = $overrides['page'];
            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::getRevisionFactory()->newRevisionFromArchiveRow( $row, 0, $title, $overrides );
        return new Revision( $rec, self::READ_NORMAL, $title );
    }
    /**
     * @since 1.19
     *
     * 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::newMutableRevisionFromArray() can be used as a temporary replacement,
     * but should be avoided.
     *
     * @param object|array $row
     * @return Revision
     */
    public static function newFromRow( $row ) {
        if ( is_array( $row ) ) {
            $rec = self::getRevisionFactory()->newMutableRevisionFromArray( $row );
        } else {
            $rec = self::getRevisionFactory()->newRevisionFromRow( $row );
        }
        return new Revision( $rec );
    }
    /**
     * Load a page revision from a given revision ID number.
     * Returns null if no such revision can be found.
     *
     * @deprecated since 1.31, use RevisionStore::getRevisionById() instead.
     *
     * @param IDatabase $db
     * @param int $id
     * @return Revision|null
     */
    public static function loadFromId( $db, $id ) {
        wfDeprecated( __METHOD__, '1.31' ); // no known callers
        $rec = self::getRevisionStore()->loadRevisionFromId( $db, $id );
        return $rec ? new Revision( $rec ) : null;
    }
    /**
     * Load either the current, or a specified, revision
     * that's attached to a given page. If not attached
     * to that page, will return null.
     *
     * @deprecated since 1.31, use RevisionStore::getRevisionByPageId() instead.
     *
     * @param IDatabase $db
     * @param int $pageid
     * @param int $id
     * @return Revision|null
     */
    public static function loadFromPageId( $db, $pageid, $id = 0 ) {
        $rec = self::getRevisionStore()->loadRevisionFromPageId( $db, $pageid, $id );
        return $rec ? new Revision( $rec ) : null;
    }
    /**
     * Load either the current, or a specified, revision
     * that's attached to a given page. If not attached
     * to that page, will return null.
     *
     * @deprecated since 1.31, use RevisionStore::getRevisionByTitle() instead.
     *
     * @param IDatabase $db
     * @param Title $title
     * @param int $id
     * @return Revision|null
     */
    public static function loadFromTitle( $db, $title, $id = 0 ) {
        $rec = self::getRevisionStore()->loadRevisionFromTitle( $db, $title, $id );
        return $rec ? new Revision( $rec ) : null;
    }
    /**
     * Load the revision for the given title with the given timestamp.
     * WARNING: Timestamps may in some circumstances not be unique,
     * so this isn't the best key to use.
     *
     * @deprecated since 1.31, use RevisionStore::getRevisionByTimestamp()
     *   or RevisionStore::loadRevisionFromTimestamp() instead.
     *
     * @param IDatabase $db
     * @param Title $title
     * @param string $timestamp
     * @return Revision|null
     */
    public static function loadFromTimestamp( $db, $title, $timestamp ) {
        $rec = self::getRevisionStore()->loadRevisionFromTimestamp( $db, $title, $timestamp );
        return $rec ? new Revision( $rec ) : null;
    }
    /**
     * Return the value of a select() JOIN conds array for the user table.
     * This will get user table rows for logged-in users.
     * @since 1.19
     * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead.
     * @return array
     */
    public static function userJoinCond() {
        global $wgActorTableSchemaMigrationStage;
        wfDeprecated( __METHOD__, '1.31' );
        if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
            // If code is using this instead of self::getQueryInfo(), there's
            // no way the join it's trying to do can work once the old fields
            // aren't being used anymore.
            throw new BadMethodCallException(
                'Cannot use ' . __METHOD__
                    . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
            );
        }
        return [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ];
    }
    /**
     * Return the value of a select() page conds array for the page table.
     * This will assure that the revision(s) are not orphaned from live pages.
     * @since 1.19
     * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead.
     * @return array
     */
    public static function pageJoinCond() {
        wfDeprecated( __METHOD__, '1.31' );
        return [ 'JOIN', [ 'page_id = rev_page' ] ];
    }
    /**
     * Return the list of revision fields that should be selected to create
     * a new revision.
     * @deprecated since 1.31, use RevisionStore::getQueryInfo() instead.
     * @return array
     */
    public static function selectFields() {
        global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage;
        global $wgMultiContentRevisionSchemaMigrationStage;
        if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
            // If code is using this instead of self::getQueryInfo(), there's a
            // decent chance it's going to try to directly access
            // $row->rev_user or $row->rev_user_text and we can't give it
            // useful values here once those aren't being used anymore.
            throw new BadMethodCallException(
                'Cannot use ' . __METHOD__
                    . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
            );
        }
        if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
            // If code is using this instead of self::getQueryInfo(), there's a
            // decent chance it's going to try to directly access
            // $row->rev_text_id or $row->rev_content_model and we can't give it
            // useful values here once those aren't being written anymore,
            // and may not exist at all.
            throw new BadMethodCallException(
                'Cannot use ' . __METHOD__ . ' when $wgMultiContentRevisionSchemaMigrationStage '
                . 'does not have SCHEMA_COMPAT_WRITE_OLD set.'
            );
        }
        wfDeprecated( __METHOD__, '1.31' );
        $fields = [
            'rev_id',
            'rev_page',
            'rev_text_id',
            'rev_timestamp',
            'rev_user_text',
            'rev_user',
            'rev_actor' => 'NULL',
            'rev_minor_edit',
            'rev_deleted',
            'rev_len',
            'rev_parent_id',
            'rev_sha1',
        ];
        $fields += CommentStore::getStore()->getFields( 'rev_comment' );
        if ( $wgContentHandlerUseDB ) {
            $fields[] = 'rev_content_format';
            $fields[] = 'rev_content_model';
        }
        return $fields;
    }
    /**
     * Return the list of revision fields that should be selected to create
     * a new revision from an archive row.
     * @deprecated since 1.31, use RevisionStore::getArchiveQueryInfo() instead.
     * @return array
     */
    public static function selectArchiveFields() {
        global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage;
        global $wgMultiContentRevisionSchemaMigrationStage;
        if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
            // If code is using this instead of self::getQueryInfo(), there's a
            // decent chance it's going to try to directly access
            // $row->ar_user or $row->ar_user_text and we can't give it
            // useful values here once those aren't being used anymore.
            throw new BadMethodCallException(
                'Cannot use ' . __METHOD__
                    . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
            );
        }
        if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
            // If code is using this instead of self::getQueryInfo(), there's a
            // decent chance it's going to try to directly access
            // $row->ar_text_id or $row->ar_content_model and we can't give it
            // useful values here once those aren't being written anymore,
            // and may not exist at all.
            throw new BadMethodCallException(
                'Cannot use ' . __METHOD__ . ' when $wgMultiContentRevisionSchemaMigrationStage '
                . 'does not have SCHEMA_COMPAT_WRITE_OLD set.'
            );
        }
        wfDeprecated( __METHOD__, '1.31' );
        $fields = [
            'ar_id',
            'ar_page_id',
            'ar_rev_id',
            'ar_text_id',
            'ar_timestamp',
            'ar_user_text',
            'ar_user',
            'ar_actor' => 'NULL',
            'ar_minor_edit',
            'ar_deleted',
            'ar_len',
            'ar_parent_id',
            'ar_sha1',
        ];
        $fields += CommentStore::getStore()->getFields( 'ar_comment' );
        if ( $wgContentHandlerUseDB ) {
            $fields[] = 'ar_content_format';
            $fields[] = 'ar_content_model';
        }
        return $fields;
    }
    /**
     * Return the list of text fields that should be selected to read the
     * revision text
     * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'text' ] ) instead.
     * @return array
     */
    public static function selectTextFields() {
        wfDeprecated( __METHOD__, '1.31' );
        return [
            'old_text',
            'old_flags'
        ];
    }
    /**
     * Return the list of page fields that should be selected from page table
     * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead.
     * @return array
     */
    public static function selectPageFields() {
        wfDeprecated( __METHOD__, '1.31' );
        return [
            'page_namespace',
            'page_title',
            'page_id',
            'page_latest',
            'page_is_redirect',
            'page_len',
        ];
    }
    /**
     * Return the list of user fields that should be selected from user table
     * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead.
     * @return array
     */
    public static function selectUserFields() {
        wfDeprecated( __METHOD__, '1.31' );
        return [ 'user_name' ];
    }
    /**
     * Return the tables, fields, and join conditions to be selected to create
     * a new revision object.
     * @since 1.31
     * @deprecated since 1.31, use RevisionStore::getQueryInfo() instead.
     * @param array $options Any combination of the following strings
     *  - 'page': Join with the page table, and select fields to identify the page
     *  - 'user': Join with the user table, and select the user name
     *  - 'text': Join with the text table, and select fields to load page text
     * @return array With three keys:
     *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
     *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
     *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
     */
    public static function getQueryInfo( $options = [] ) {
        return self::getRevisionStore()->getQueryInfo( $options );
    }
    /**
     * Return the tables, fields, and join conditions to be selected to create
     * a new archived revision object.
     * @since 1.31
     * @deprecated since 1.31, use RevisionStore::getArchiveQueryInfo() instead.
     * @return array With three keys:
     *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
     *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
     *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
     */
    public static function getArchiveQueryInfo() {
        return self::getRevisionStore()->getArchiveQueryInfo();
    }
    /**
     * 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
     */
    public static function getParentLengths( $db, array $revIds ) {
        return self::getRevisionStore()->listRevisionSizes( $db, $revIds );
    }
    /**
     * @param object|array|RevisionRecord $row Either a database row or an array
     * @param int $queryFlags
     * @param Title|null $title
     *
     * @private
     */
    function __construct( $row, $queryFlags = 0, Title $title = null ) {
        global $wgUser;
        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;
            }
            $this->mRecord = self::getRevisionFactory()->newMutableRevisionFromArray(
                $row,
                $queryFlags,
                $this->ensureTitle( $row, $queryFlags, $title )
            );
        } elseif ( is_object( $row ) ) {
            $this->mRecord = self::getRevisionFactory()->newRevisionFromRow(
                $row,
                $queryFlags,
                $this->ensureTitle( $row, $queryFlags, $title )
            );
        } else {
            throw new InvalidArgumentException(
                '$row must be a row object, an associative array, or a RevisionRecord'
            );
        }
        Assert::postcondition( $this->mRecord !== null, 'Failed to construct a RevisionRecord' );
    }
    /**
     * 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 ) {