32use Wikimedia\Assert\Assert;
56 const RAW = RevisionRecord::RAW;
65 return MediaWikiServices::getInstance()->getRevisionStoreFactory()
66 ->getRevisionStore( $wiki );
68 return MediaWikiServices::getInstance()->getRevisionStore();
76 return MediaWikiServices::getInstance()->getRevisionLookup();
83 return MediaWikiServices::getInstance()->getRevisionFactory();
93 $store = MediaWikiServices::getInstance()
94 ->getBlobStoreFactory()
95 ->newSqlBlobStore( $wiki );
98 throw new RuntimeException(
99 'The backwards compatibility code in Revision currently requires the BlobStore '
100 .
'service to be an SqlBlobStore instance, but it is a ' . get_class( $store )
120 $rec = self::getRevisionLookup()->getRevisionById( $id, $flags );
121 return $rec ?
new Revision( $rec, $flags ) :
null;
139 $rec = self::getRevisionLookup()->getRevisionByTitle( $linkTarget, $id, $flags );
140 return $rec ?
new Revision( $rec, $flags ) :
null;
158 $rec = self::getRevisionLookup()->getRevisionByPageId( $pageId, $revId, $flags );
159 return $rec ?
new Revision( $rec, $flags ) :
null;
179 if ( array_key_exists(
'page', $overrides ) ) {
180 $overrides[
'page_id'] = $overrides[
'page'];
181 unset( $overrides[
'page'] );
190 if ( isset( $overrides[
'title'] ) ) {
191 if ( !( $overrides[
'title'] instanceof
Title ) ) {
192 throw new MWException(
'title field override must contain a Title object.' );
195 $title = $overrides[
'title'];
198 if ( isset( $row->ar_namespace ) && isset( $row->ar_title ) ) {
199 $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
201 throw new InvalidArgumentException(
202 'A Title or ar_namespace and ar_title must be given'
207 $rec = self::getRevisionFactory()->newRevisionFromArchiveRow( $row, 0,
$title, $overrides );
224 if ( is_array( $row ) ) {
225 $rec = self::getRevisionFactory()->newMutableRevisionFromArray( $row );
227 $rec = self::getRevisionFactory()->newRevisionFromRow( $row );
245 $rec = self::getRevisionStore()->loadRevisionFromId( $db, $id );
246 return $rec ?
new Revision( $rec ) :
null;
262 $rec = self::getRevisionStore()->loadRevisionFromPageId( $db, $pageid, $id );
263 return $rec ?
new Revision( $rec ) :
null;
279 $rec = self::getRevisionStore()->loadRevisionFromTitle( $db,
$title, $id );
280 return $rec ?
new Revision( $rec ) :
null;
297 $rec = self::getRevisionStore()->loadRevisionFromTimestamp( $db,
$title, $timestamp );
298 return $rec ?
new Revision( $rec ) :
null;
316 return self::getRevisionStore()->getQueryInfo( $options );
330 return self::getRevisionStore()->getArchiveQueryInfo();
343 return self::getRevisionStore()->listRevisionSizes( $db, $revIds );
357 $this->mRecord = $row;
358 } elseif ( is_array( $row ) ) {
361 if ( !isset( $row[
'user'] ) && !isset( $row[
'user_text'] ) ) {
362 $row[
'user'] = $wgUser;
365 $this->mRecord = self::getRevisionFactory()->newMutableRevisionFromArray(
370 } elseif ( is_object( $row ) ) {
371 $this->mRecord = self::getRevisionFactory()->newRevisionFromRow(
377 throw new InvalidArgumentException(
378 '$row must be a row object, an associative array, or a RevisionRecord'
382 Assert::postcondition( $this->mRecord !==
null,
'Failed to construct a RevisionRecord' );
400 if ( is_array( $row ) ) {
401 if ( isset( $row[
'title'] ) ) {
402 if ( !( $row[
'title'] instanceof
Title ) ) {
403 throw new MWException(
'title field must contain a Title object.' );
406 return $row[
'title'];
409 $pageId = $row[
'page'] ?? 0;
410 $revId = $row[
'id'] ?? 0;
412 $pageId = $row->rev_page ?? 0;
413 $revId = $row->rev_id ?? 0;
417 $title = self::getRevisionStore()->getTitle( $pageId, $revId, $queryFlags );
424 $title->resetArticleID( $pageId );
434 return $this->mRecord;
443 return $this->mRecord->getId();
460 $this->mRecord->setId( intval( $id ) );
462 throw new MWException( __METHOD__ .
' is not supported on this instance' );
482 $user = User::newFromAnyId( intval( $id ), $name,
null );
483 $this->mRecord->setUser( $user );
485 throw new MWException( __METHOD__ .
' is not supported on this instance' );
493 return $this->mRecord->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
510 return $slot->hasAddress()
511 ? self::getBlobStore()->getTextIdFromAddress( $slot->getAddress() )
522 return $this->mRecord->getParentId();
532 return $this->mRecord->getSize();
545 return $this->mRecord->getSha1();
560 $linkTarget = $this->mRecord->getPageAsLinkTarget();
561 return Title::newFromLinkTarget( $linkTarget );
572 if ( !
$title->equals( $this->getTitle() ) ) {
573 throw new InvalidArgumentException(
575 .
' is not the same as '
576 . $this->mRecord->getPageAsLinkTarget()->__toString()
587 return $this->mRecord->getPageId();
603 public function getUser( $audience = self::FOR_PUBLIC,
User $user =
null ) {
606 if ( $audience === self::FOR_THIS_USER && !$user ) {
610 $user = $this->mRecord->getUser( $audience, $user );
611 return $user ? $user->getId() : 0;
630 if ( $audience === self::FOR_THIS_USER && !$user ) {
634 $user = $this->mRecord->getUser( $audience, $user );
635 return $user ? $user->getName() :
'';
652 if ( $audience === self::FOR_THIS_USER && !$user ) {
656 $comment = $this->mRecord->getComment( $audience, $user );
657 return $comment ===
null ? null : $comment->text;
664 return $this->mRecord->isMinor();
671 return self::getRevisionStore()->getRcIdIfUnpatrolled( $this->mRecord );
684 return self::getRevisionStore()->getRecentChange( $this->mRecord, $flags );
693 return $this->mRecord->isDeleted( $field );
702 return $this->mRecord->getVisibility();
722 if ( $audience === self::FOR_THIS_USER && !$user ) {
727 return $this->mRecord->getContent( SlotRecord::MAIN, $audience, $user );
744 return $slot->getContent()->serialize();
777 if ( $format ===
null ) {
799 return $this->mRecord->getTimestamp();
815 $rec = self::getRevisionLookup()->getPreviousRevision( $this->mRecord );
816 return $rec ?
new Revision( $rec, self::READ_NORMAL, $this->
getTitle() ) :
null;
825 $rec = self::getRevisionLookup()->getNextRevision( $this->mRecord );
826 return $rec ?
new Revision( $rec, self::READ_NORMAL, $this->
getTitle() ) :
null;
857 $textField = $prefix .
'text';
858 $flagsField = $prefix .
'flags';
860 if ( isset( $row->$textField ) ) {
866 throw new LogicException(
867 'Cannot use ' . __METHOD__ .
' with the ' . $textField .
' field when'
868 .
' $wgMultiContentRevisionSchemaMigrationStage does not include'
869 .
' SCHEMA_COMPAT_WRITE_OLD. The field may not be populated for all revisions!'
873 $text = $row->$textField;
880 wfDeprecated( __METHOD__ .
' (MCR without SCHEMA_COMPAT_WRITE_OLD)',
'1.32' );
883 $store = self::getRevisionStore( $wiki );
884 $rev = $prefix ===
'ar_'
885 ? $store->newRevisionFromArchiveRow( $row )
886 : $store->newRevisionFromRow( $row );
888 $content = $rev->getContent( SlotRecord::MAIN );
892 if ( isset( $row->$flagsField ) ) {
893 $flags = explode(
',', $row->$flagsField );
898 $cacheKey = isset( $row->old_id )
899 ? SqlBlobStore::makeAddressFromTextId( $row->old_id )
902 $revisionText = self::getBlobStore( $wiki )->expandBlob( $text, $flags, $cacheKey );
904 if ( $revisionText ===
false ) {
905 if ( isset( $row->old_id ) ) {
906 wfLogWarning( __METHOD__ .
": Bad data in text row {$row->old_id}! " );
908 wfLogWarning( __METHOD__ .
": Bad data in text row! " );
913 return $revisionText;
927 return self::getBlobStore()->compressData( $text );
938 if ( $text ===
false ) {
943 return self::getBlobStore()->decompressData( $text, $flags );
960 if ( $this->mRecord->getUser( RevisionRecord::RAW ) ===
null ) {
962 $this->mRecord->setUser( $wgUser );
964 throw new MWException(
'Cannot insert revision with no associated user.' );
968 $rec = self::getRevisionStore()->insertRevisionOn( $this->mRecord, $dbw );
970 $this->mRecord = $rec;
971 Assert::postcondition( $this->mRecord !==
null,
'Failed to acquire a RevisionRecord' );
973 return $rec->getId();
982 return SlotRecord::base36Sha1( $text );
1006 $comment = CommentStoreComment::newUnsavedComment( $summary,
null );
1008 $title = Title::newFromID( $pageId, Title::READ_LATEST );
1013 $rec = self::getRevisionStore()->newNullRevision( $dbw,
$title, $comment, $minor, $user );
1015 return $rec ?
new Revision( $rec ) :
null;
1029 return self::userCanBitfield( $this->
getVisibility(), $field, $user );
1055 return RevisionRecord::userCanBitfield( $bitfield, $field, $user,
$title );
1067 return self::getRevisionStore()->getTimestampFromId( $id, $flags );
1078 return self::getRevisionStore()->countRevisionsByPageId( $db, $id );
1089 return self::getRevisionStore()->countRevisionsByTitle( $db,
$title );
1109 if ( is_int( $db ) ) {
1113 return self::getRevisionStore()->userWasLastToEdit( $db, $pageId, $userId, $since );
1132 : Title::newFromID( $pageIdOrTitle );
1138 $record = self::getRevisionLookup()->getKnownCurrentRevision(
$title, $revId );
1139 return $record ?
new Revision( $record ) :
false;
int $wgMultiContentRevisionSchemaMigrationStage
RevisionStore table schema migration stage (content, slots, content_models & slot_roles tables).
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
getRecentChange( $flags=0)
Get the RC object belonging to the current revision, if there's one.
getUserText( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's username if it's available to the specified audience.
getTitle()
Returns the title of the page associated with this entry.
getPrevious()
Get previous revision for this title.
ensureTitle( $row, $queryFlags, $title=null)
Make sure we have some Title object for use by the constructor.
getSize()
Returns the length of the text in this revision, or null if unknown.
getSerializedData()
Get original serialized data (without checking view restrictions)
static compressRevisionText(&$text)
If $wgCompressRevisions is enabled, we will compress data.
static decompressRevisionText( $text, $flags)
Re-converts revision text according to it's flags.
setUserIdAndName( $id, $name)
Set the user ID/name.
getContentHandler()
Returns the content handler appropriate for this revision's content model.
static newKnownCurrent(IDatabase $db, $pageIdOrTitle, $revId=0)
Load a revision based on a known page ID and current revision ID from the DB.
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row.
getComment( $audience=self::FOR_PUBLIC, User $user=null)
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
getNext()
Get next revision for this title.
getTextId()
Get the ID of the row of the text table that contains the content of the revision's main slot,...
static getRevisionStore( $wiki=false)
static newFromPageId( $pageId, $revId=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given page ID.
getContentFormat()
Returns the content format for the main slot of this revision.
static loadFromTimestamp( $db, $title, $timestamp)
Load the revision for the given title with the given timestamp.
static getRevisionFactory()
getPage()
Get the page ID.
static getArchiveQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archived revision objec...
static newNullRevision( $dbw, $pageId, $summary, $minor, $user=null)
Create a new null-revision for insertion into a page's history.
static loadFromId( $db, $id)
Load a page revision from a given revision ID number.
static getTimestampFromId( $title, $id, $flags=0)
Get rev_timestamp from rev_id, without loading the rest of the row.
getContentModel()
Returns the content model for the main slot of this revision.
static countByPageId( $db, $id)
Get count of revisions per page...not very efficient.
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's user id if it's available to the specified audience.
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
getContent( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision content if it's available to the specified audience.
static countByTitle( $db, $title)
Get count of revisions per page...not very efficient.
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
static base36Sha1( $text)
Get the base 36 SHA-1 value for a string of text.
getSha1()
Returns the base36 sha1 of the content in this revision, or null if unknown.
static loadFromPageId( $db, $pageid, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
static userCanBitfield( $bitfield, $field, User $user=null, Title $title=null)
Determine if the current user is allowed to view a particular field of this revision,...
getVisibility()
Get the deletion bitfield of the revision.
setTitle( $title)
Set the title of the revision.
insertOn( $dbw)
Insert a new revision into the database, returning the new revision ID number on success and dies hor...
__construct( $row, $queryFlags=0, Title $title=null)
static userWasLastToEdit( $db, $pageId, $userId, $since)
Check if no edits were made by other users since the time a user started editing the page.
static getParentLengths( $db, array $revIds)
Do a batched query to get the parent revision lengths.
static getRevisionLookup()
userCan( $field, User $user=null)
Determine if the current user is allowed to view a particular field of this revision,...
static getBlobStore( $wiki=false)
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
getParentId()
Get parent revision ID (the original previous page revision)
setId( $id)
Set the revision ID.
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Represents a title within MediaWiki.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
const SCHEMA_COMPAT_WRITE_OLD
Interface for database access objects.