123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041 |
- <?php
- /**
- * @todo document
- * @file
- */
- /**
- * @todo document
- */
- class Revision {
- const DELETED_TEXT = 1;
- const DELETED_COMMENT = 2;
- const DELETED_USER = 4;
- const DELETED_RESTRICTED = 8;
- // Audience options for Revision::getText()
- const FOR_PUBLIC = 1;
- const FOR_THIS_USER = 2;
- const RAW = 3;
- /**
- * Load a page revision from a given revision ID number.
- * Returns null if no such revision can be found.
- *
- * @param int $id
- * @access public
- * @static
- */
- public static function newFromId( $id ) {
- return Revision::newFromConds(
- array( 'page_id=rev_page',
- 'rev_id' => intval( $id ) ) );
- }
- /**
- * Load either the current, or a specified, revision
- * that's attached to a given title. If not attached
- * to that title, will return null.
- *
- * @param Title $title
- * @param int $id
- * @return Revision
- */
- public static function newFromTitle( $title, $id = 0 ) {
- $conds = array(
- 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey()
- );
- if ( $id ) {
- // Use the specified ID
- $conds['rev_id'] = $id;
- } elseif ( wfGetLB()->getServerCount() > 1 ) {
- // Get the latest revision ID from the master
- $dbw = wfGetDB( DB_MASTER );
- $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
- if ( $latest === false ) {
- // Page does not exist
- return null;
- }
- $conds['rev_id'] = $latest;
- } else {
- // Use a join to get the latest revision
- $conds[] = 'rev_id=page_latest';
- }
- $conds[] = 'page_id=rev_page';
- return Revision::newFromConds( $conds );
- }
- /**
- * Load a page revision from a given revision ID number.
- * Returns null if no such revision can be found.
- *
- * @param Database $db
- * @param int $id
- * @access public
- * @static
- */
- public static function loadFromId( $db, $id ) {
- return Revision::loadFromConds( $db,
- array( 'page_id=rev_page',
- 'rev_id' => intval( $id ) ) );
- }
- /**
- * Load either the current, or a specified, revision
- * that's attached to a given page. If not attached
- * to that page, will return null.
- *
- * @param Database $db
- * @param int $pageid
- * @param int $id
- * @return Revision
- * @access public
- * @static
- */
- public static function loadFromPageId( $db, $pageid, $id = 0 ) {
- $conds=array('page_id=rev_page','rev_page'=>intval( $pageid ), 'page_id'=>intval( $pageid ));
- if( $id ) {
- $conds['rev_id']=intval($id);
- } else {
- $conds[]='rev_id=page_latest';
- }
- return Revision::loadFromConds( $db, $conds );
- }
- /**
- * Load either the current, or a specified, revision
- * that's attached to a given page. If not attached
- * to that page, will return null.
- *
- * @param Database $db
- * @param Title $title
- * @param int $id
- * @return Revision
- * @access public
- * @static
- */
- public static function loadFromTitle( $db, $title, $id = 0 ) {
- if( $id ) {
- $matchId = intval( $id );
- } else {
- $matchId = 'page_latest';
- }
- return Revision::loadFromConds(
- $db,
- array( "rev_id=$matchId",
- 'page_id=rev_page',
- 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey() ) );
- }
- /**
- * 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.
- *
- * @param Database $db
- * @param Title $title
- * @param string $timestamp
- * @return Revision
- * @access public
- * @static
- */
- public static function loadFromTimestamp( $db, $title, $timestamp ) {
- return Revision::loadFromConds(
- $db,
- array( 'rev_timestamp' => $db->timestamp( $timestamp ),
- 'page_id=rev_page',
- 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey() ) );
- }
- /**
- * Given a set of conditions, fetch a revision.
- *
- * @param array $conditions
- * @return Revision
- * @access private
- * @static
- */
- private static function newFromConds( $conditions ) {
- $db = wfGetDB( DB_SLAVE );
- $row = Revision::loadFromConds( $db, $conditions );
- if( is_null( $row ) && wfGetLB()->getServerCount() > 1 ) {
- $dbw = wfGetDB( DB_MASTER );
- $row = Revision::loadFromConds( $dbw, $conditions );
- }
- return $row;
- }
- /**
- * Given a set of conditions, fetch a revision from
- * the given database connection.
- *
- * @param Database $db
- * @param array $conditions
- * @return Revision
- * @access private
- * @static
- */
- private static function loadFromConds( $db, $conditions ) {
- $res = Revision::fetchFromConds( $db, $conditions );
- if( $res ) {
- $row = $res->fetchObject();
- $res->free();
- if( $row ) {
- $ret = new Revision( $row );
- return $ret;
- }
- }
- $ret = null;
- return $ret;
- }
- /**
- * Return a wrapper for a series of database rows to
- * fetch all of a given page's revisions in turn.
- * Each row can be fed to the constructor to get objects.
- *
- * @param Title $title
- * @return ResultWrapper
- * @access public
- * @static
- */
- public static function fetchAllRevisions( $title ) {
- return Revision::fetchFromConds(
- wfGetDB( DB_SLAVE ),
- array( 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey(),
- 'page_id=rev_page' ) );
- }
- /**
- * Return a wrapper for a series of database rows to
- * fetch all of a given page's revisions in turn.
- * Each row can be fed to the constructor to get objects.
- *
- * @param Title $title
- * @return ResultWrapper
- * @access public
- * @static
- */
- public static function fetchRevision( $title ) {
- return Revision::fetchFromConds(
- wfGetDB( DB_SLAVE ),
- array( 'rev_id=page_latest',
- 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey(),
- 'page_id=rev_page' ) );
- }
- /**
- * Given a set of conditions, return a ResultWrapper
- * which will return matching database rows with the
- * fields necessary to build Revision objects.
- *
- * @param Database $db
- * @param array $conditions
- * @return ResultWrapper
- * @access private
- * @static
- */
- private static function fetchFromConds( $db, $conditions ) {
- $fields = self::selectFields();
- $fields[] = 'page_namespace';
- $fields[] = 'page_title';
- $fields[] = 'page_latest';
- $res = $db->select(
- array( 'page', 'revision' ),
- $fields,
- $conditions,
- __METHOD__,
- array( 'LIMIT' => 1 ) );
- $ret = $db->resultObject( $res );
- return $ret;
- }
- /**
- * Return the list of revision fields that should be selected to create
- * a new revision.
- */
- static function selectFields() {
- return array(
- 'rev_id',
- 'rev_page',
- 'rev_text_id',
- 'rev_timestamp',
- 'rev_comment',
- 'rev_user_text,'.
- 'rev_user',
- 'rev_minor_edit',
- 'rev_deleted',
- 'rev_len',
- 'rev_parent_id'
- );
- }
-
- /**
- * Return the list of text fields that should be selected to read the
- * revision text
- */
- static function selectTextFields() {
- return array(
- 'old_text',
- 'old_flags'
- );
- }
- /**
- * Return the list of page fields that should be selected from page table
- */
- static function selectPageFields() {
- return array(
- 'page_namespace',
- 'page_title',
- 'page_latest'
- );
- }
- /**
- * @param object $row
- * @access private
- */
- function Revision( $row ) {
- if( is_object( $row ) ) {
- $this->mId = intval( $row->rev_id );
- $this->mPage = intval( $row->rev_page );
- $this->mTextId = intval( $row->rev_text_id );
- $this->mComment = $row->rev_comment;
- $this->mUserText = $row->rev_user_text;
- $this->mUser = intval( $row->rev_user );
- $this->mMinorEdit = intval( $row->rev_minor_edit );
- $this->mTimestamp = $row->rev_timestamp;
- $this->mDeleted = intval( $row->rev_deleted );
- if( !isset( $row->rev_parent_id ) )
- $this->mParentId = is_null($row->rev_parent_id) ? null : 0;
- else
- $this->mParentId = intval( $row->rev_parent_id );
- if( !isset( $row->rev_len ) || is_null( $row->rev_len ) )
- $this->mSize = null;
- else
- $this->mSize = intval( $row->rev_len );
- if( isset( $row->page_latest ) ) {
- $this->mCurrent = ( $row->rev_id == $row->page_latest );
- $this->mTitle = Title::makeTitle( $row->page_namespace, $row->page_title );
- $this->mTitle->resetArticleID( $this->mPage );
- } else {
- $this->mCurrent = false;
- $this->mTitle = null;
- }
- // Lazy extraction...
- $this->mText = null;
- if( isset( $row->old_text ) ) {
- $this->mTextRow = $row;
- } else {
- // 'text' table row entry will be lazy-loaded
- $this->mTextRow = null;
- }
- } elseif( is_array( $row ) ) {
- // Build a new revision to be saved...
- global $wgUser;
- $this->mId = isset( $row['id'] ) ? intval( $row['id'] ) : null;
- $this->mPage = isset( $row['page'] ) ? intval( $row['page'] ) : null;
- $this->mTextId = isset( $row['text_id'] ) ? intval( $row['text_id'] ) : null;
- $this->mUserText = isset( $row['user_text'] ) ? strval( $row['user_text'] ) : $wgUser->getName();
- $this->mUser = isset( $row['user'] ) ? intval( $row['user'] ) : $wgUser->getId();
- $this->mMinorEdit = isset( $row['minor_edit'] ) ? intval( $row['minor_edit'] ) : 0;
- $this->mTimestamp = isset( $row['timestamp'] ) ? strval( $row['timestamp'] ) : wfTimestamp( TS_MW );
- $this->mDeleted = isset( $row['deleted'] ) ? intval( $row['deleted'] ) : 0;
- $this->mSize = isset( $row['len'] ) ? intval( $row['len'] ) : null;
- $this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null;
- // Enforce spacing trimming on supplied text
- $this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null;
- $this->mText = isset( $row['text'] ) ? rtrim( strval( $row['text'] ) ) : null;
- $this->mTextRow = null;
- $this->mTitle = null; # Load on demand if needed
- $this->mCurrent = false;
- # If we still have no len_size, see it we have the text to figure it out
- if ( !$this->mSize )
- $this->mSize = is_null($this->mText) ? null : strlen($this->mText);
- } else {
- throw new MWException( 'Revision constructor passed invalid row format.' );
- }
- $this->mUnpatrolled = NULL;
- }
- /**#@+
- * @access public
- */
- /**
- * Get revision ID
- * @return int
- */
- public function getId() {
- return $this->mId;
- }
- /**
- * Get text row ID
- * @return int
- */
- public function getTextId() {
- return $this->mTextId;
- }
- /**
- * Get parent revision ID (the original previous page revision)
- * @return int
- */
- public function getParentId() {
- return $this->mParentId;
- }
- /**
- * Returns the length of the text in this revision, or null if unknown.
- * @return int
- */
- public function getSize() {
- return $this->mSize;
- }
- /**
- * Returns the title of the page associated with this entry.
- * @return Title
- */
- public function getTitle() {
- if( isset( $this->mTitle ) ) {
- return $this->mTitle;
- }
- $dbr = wfGetDB( DB_SLAVE );
- $row = $dbr->selectRow(
- array( 'page', 'revision' ),
- array( 'page_namespace', 'page_title' ),
- array( 'page_id=rev_page',
- 'rev_id' => $this->mId ),
- 'Revision::getTitle' );
- if( $row ) {
- $this->mTitle = Title::makeTitle( $row->page_namespace,
- $row->page_title );
- }
- return $this->mTitle;
- }
- /**
- * Set the title of the revision
- * @param Title $title
- */
- public function setTitle( $title ) {
- $this->mTitle = $title;
- }
- /**
- * Get the page ID
- * @return int
- */
- public function getPage() {
- return $this->mPage;
- }
- /**
- * Fetch revision's user id if it's available to the specified audience.
- * If the specified audience does not have access to it, zero will be
- * returned.
- *
- * @param integer $audience One of:
- * Revision::FOR_PUBLIC to be displayed to all users
- * Revision::FOR_THIS_USER to be displayed to $wgUser
- * Revision::RAW get the ID regardless of permissions
- *
- *
- * @return int
- */
- public function getUser( $audience = self::FOR_PUBLIC ) {
- if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_USER ) ) {
- return 0;
- } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_USER ) ) {
- return 0;
- } else {
- return $this->mUser;
- }
- }
- /**
- * Fetch revision's user id without regard for the current user's permissions
- * @return string
- */
- public function getRawUser() {
- return $this->mUser;
- }
- /**
- * Fetch revision's username if it's available to the specified audience.
- * If the specified audience does not have access to the username, an
- * empty string will be returned.
- *
- * @param integer $audience One of:
- * Revision::FOR_PUBLIC to be displayed to all users
- * Revision::FOR_THIS_USER to be displayed to $wgUser
- * Revision::RAW get the text regardless of permissions
- *
- * @return string
- */
- public function getUserText( $audience = self::FOR_PUBLIC ) {
- if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_USER ) ) {
- return "";
- } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_USER ) ) {
- return "";
- } else {
- return $this->mUserText;
- }
- }
- /**
- * Fetch revision's username without regard for view restrictions
- * @return string
- */
- public function getRawUserText() {
- return $this->mUserText;
- }
- /**
- * Fetch revision comment if it's available to the specified audience.
- * If the specified audience does not have access to the comment, an
- * empty string will be returned.
- *
- * @param integer $audience One of:
- * Revision::FOR_PUBLIC to be displayed to all users
- * Revision::FOR_THIS_USER to be displayed to $wgUser
- * Revision::RAW get the text regardless of permissions
- *
- * @return string
- */
- function getComment( $audience = self::FOR_PUBLIC ) {
- if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_COMMENT ) ) {
- return "";
- } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_COMMENT ) ) {
- return "";
- } else {
- return $this->mComment;
- }
- }
- /**
- * Fetch revision comment without regard for the current user's permissions
- * @return string
- */
- public function getRawComment() {
- return $this->mComment;
- }
- /**
- * @return bool
- */
- public function isMinor() {
- return (bool)$this->mMinorEdit;
- }
-
- /**
- * @return int rcid of the unpatrolled row, zero if there isn't one
- */
- public function isUnpatrolled() {
- if( $this->mUnpatrolled !== NULL ) {
- return $this->mUnpatrolled;
- }
- $dbr = wfGetDB( DB_SLAVE );
- $this->mUnpatrolled = $dbr->selectField( 'recentchanges',
- 'rc_id',
- array( // Add redundant user,timestamp condition so we can use the existing index
- 'rc_user_text' => $this->getRawUserText(),
- 'rc_timestamp' => $dbr->timestamp( $this->getTimestamp() ),
- 'rc_this_oldid' => $this->getId(),
- 'rc_patrolled' => 0
- ),
- __METHOD__
- );
- return (int)$this->mUnpatrolled;
- }
- /**
- * int $field one of DELETED_* bitfield constants
- * @return bool
- */
- public function isDeleted( $field ) {
- return ($this->mDeleted & $field) == $field;
- }
-
- /**
- * Get the deletion bitfield of the revision
- */
- public function getVisibility() {
- return (int)$this->mDeleted;
- }
- /**
- * Fetch revision text if it's available to the specified audience.
- * If the specified audience does not have the ability to view this
- * revision, an empty string will be returned.
- *
- * @param integer $audience One of:
- * Revision::FOR_PUBLIC to be displayed to all users
- * Revision::FOR_THIS_USER to be displayed to $wgUser
- * Revision::RAW get the text regardless of permissions
- *
- *
- * @return string
- */
- public function getText( $audience = self::FOR_PUBLIC ) {
- if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) {
- return "";
- } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT ) ) {
- return "";
- } else {
- return $this->getRawText();
- }
- }
- /**
- * Alias for getText(Revision::FOR_THIS_USER)
- */
- public function revText() {
- return $this->getText( self::FOR_THIS_USER );
- }
- /**
- * Fetch revision text without regard for view restrictions
- * @return string
- */
- public function getRawText() {
- if( is_null( $this->mText ) ) {
- // Revision text is immutable. Load on demand:
- $this->mText = $this->loadText();
- }
- return $this->mText;
- }
- /**
- * @return string
- */
- public function getTimestamp() {
- return wfTimestamp(TS_MW, $this->mTimestamp);
- }
- /**
- * @return bool
- */
- public function isCurrent() {
- return $this->mCurrent;
- }
- /**
- * Get previous revision for this title
- * @return Revision
- */
- public function getPrevious() {
- if( $this->getTitle() ) {
- $prev = $this->getTitle()->getPreviousRevisionID( $this->getId() );
- if( $prev ) {
- return Revision::newFromTitle( $this->getTitle(), $prev );
- }
- }
- return null;
- }
- /**
- * @return Revision
- */
- public function getNext() {
- if( $this->getTitle() ) {
- $next = $this->getTitle()->getNextRevisionID( $this->getId() );
- if ( $next ) {
- return Revision::newFromTitle( $this->getTitle(), $next );
- }
- }
- return null;
- }
- /**
- * Get previous revision Id for this page_id
- * This is used to populate rev_parent_id on save
- * @param Database $db
- * @return int
- */
- private function getPreviousRevisionId( $db ) {
- if( is_null($this->mPage) ) {
- return 0;
- }
- # Use page_latest if ID is not given
- if( !$this->mId ) {
- $prevId = $db->selectField( 'page', 'page_latest',
- array( 'page_id' => $this->mPage ),
- __METHOD__ );
- } else {
- $prevId = $db->selectField( 'revision', 'rev_id',
- array( 'rev_page' => $this->mPage, 'rev_id < ' . $this->mId ),
- __METHOD__,
- array( 'ORDER BY' => 'rev_id DESC' ) );
- }
- return intval($prevId);
- }
- /**
- * Get revision text associated with an old or archive row
- * $row is usually an object from wfFetchRow(), both the flags and the text
- * field must be included
- *
- * @param object $row The text data
- * @param string $prefix table prefix (default 'old_')
- * @return string $text|false the text requested
- */
- public static function getRevisionText( $row, $prefix = 'old_' ) {
- wfProfileIn( __METHOD__ );
- # Get data
- $textField = $prefix . 'text';
- $flagsField = $prefix . 'flags';
- if( isset( $row->$flagsField ) ) {
- $flags = explode( ',', $row->$flagsField );
- } else {
- $flags = array();
- }
- if( isset( $row->$textField ) ) {
- $text = $row->$textField;
- } else {
- wfProfileOut( __METHOD__ );
- return false;
- }
- # Use external methods for external objects, text in table is URL-only then
- if ( in_array( 'external', $flags ) ) {
- $url=$text;
- @list(/* $proto */,$path)=explode('://',$url,2);
- if ($path=="") {
- wfProfileOut( __METHOD__ );
- return false;
- }
- $text=ExternalStore::fetchFromURL($url);
- }
- // If the text was fetched without an error, convert it
- if ( $text !== false ) {
- if( in_array( 'gzip', $flags ) ) {
- # Deal with optional compression of archived pages.
- # This can be done periodically via maintenance/compressOld.php, and
- # as pages are saved if $wgCompressRevisions is set.
- $text = gzinflate( $text );
- }
- if( in_array( 'object', $flags ) ) {
- # Generic compressed storage
- $obj = unserialize( $text );
- if ( !is_object( $obj ) ) {
- // Invalid object
- wfProfileOut( __METHOD__ );
- return false;
- }
- $text = $obj->getText();
- }
- global $wgLegacyEncoding;
- if( $wgLegacyEncoding && !in_array( 'utf-8', $flags ) && !in_array( 'utf8', $flags ) ) {
- # Old revisions kept around in a legacy encoding?
- # Upconvert on demand.
- # ("utf8" checked for compatibility with some broken
- # conversion scripts 2008-12-30)
- global $wgInputEncoding, $wgContLang;
- $text = $wgContLang->iconv( $wgLegacyEncoding, $wgInputEncoding, $text );
- }
- }
- wfProfileOut( __METHOD__ );
- return $text;
- }
- /**
- * If $wgCompressRevisions is enabled, we will compress data.
- * The input string is modified in place.
- * Return value is the flags field: contains 'gzip' if the
- * data is compressed, and 'utf-8' if we're saving in UTF-8
- * mode.
- *
- * @param mixed $text reference to a text
- * @return string
- */
- public static function compressRevisionText( &$text ) {
- global $wgCompressRevisions;
- $flags = array();
- # Revisions not marked this way will be converted
- # on load if $wgLegacyCharset is set in the future.
- $flags[] = 'utf-8';
- if( $wgCompressRevisions ) {
- if( function_exists( 'gzdeflate' ) ) {
- $text = gzdeflate( $text );
- $flags[] = 'gzip';
- } else {
- wfDebug( "Revision::compressRevisionText() -- no zlib support, not compressing\n" );
- }
- }
- return implode( ',', $flags );
- }
- /**
- * Insert a new revision into the database, returning the new revision ID
- * number on success and dies horribly on failure.
- *
- * @param Database $dbw
- * @return int
- */
- public function insertOn( $dbw ) {
- global $wgDefaultExternalStore;
- wfProfileIn( __METHOD__ );
- $data = $this->mText;
- $flags = Revision::compressRevisionText( $data );
- # Write to external storage if required
- if( $wgDefaultExternalStore ) {
- // Store and get the URL
- $data = ExternalStore::insertToDefault( $data );
- if( !$data ) {
- throw new MWException( "Unable to store text to external storage" );
- }
- if( $flags ) {
- $flags .= ',';
- }
- $flags .= 'external';
- }
- # Record the text (or external storage URL) to the text table
- if( !isset( $this->mTextId ) ) {
- $old_id = $dbw->nextSequenceValue( 'text_old_id_val' );
- $dbw->insert( 'text',
- array(
- 'old_id' => $old_id,
- 'old_text' => $data,
- 'old_flags' => $flags,
- ), __METHOD__
- );
- $this->mTextId = $dbw->insertId();
- }
- # Record the edit in revisions
- $rev_id = isset( $this->mId )
- ? $this->mId
- : $dbw->nextSequenceValue( 'rev_rev_id_val' );
- $dbw->insert( 'revision',
- array(
- 'rev_id' => $rev_id,
- 'rev_page' => $this->mPage,
- 'rev_text_id' => $this->mTextId,
- 'rev_comment' => $this->mComment,
- 'rev_minor_edit' => $this->mMinorEdit ? 1 : 0,
- 'rev_user' => $this->mUser,
- 'rev_user_text' => $this->mUserText,
- 'rev_timestamp' => $dbw->timestamp( $this->mTimestamp ),
- 'rev_deleted' => $this->mDeleted,
- 'rev_len' => $this->mSize,
- 'rev_parent_id' => is_null($this->mParentId) ?
- $this->getPreviousRevisionId( $dbw ) : $this->mParentId
- ), __METHOD__
- );
- $this->mId = !is_null($rev_id) ? $rev_id : $dbw->insertId();
-
- wfRunHooks( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
-
- wfProfileOut( __METHOD__ );
- return $this->mId;
- }
- /**
- * Lazy-load the revision's text.
- * Currently hardcoded to the 'text' table storage engine.
- *
- * @return string
- */
- private function loadText() {
- wfProfileIn( __METHOD__ );
- // Caching may be beneficial for massive use of external storage
- global $wgRevisionCacheExpiry, $wgMemc;
- $key = wfMemcKey( 'revisiontext', 'textid', $this->getTextId() );
- if( $wgRevisionCacheExpiry ) {
- $text = $wgMemc->get( $key );
- if( is_string( $text ) ) {
- wfProfileOut( __METHOD__ );
- return $text;
- }
- }
- // If we kept data for lazy extraction, use it now...
- if ( isset( $this->mTextRow ) ) {
- $row = $this->mTextRow;
- $this->mTextRow = null;
- } else {
- $row = null;
- }
- if( !$row ) {
- // Text data is immutable; check slaves first.
- $dbr = wfGetDB( DB_SLAVE );
- $row = $dbr->selectRow( 'text',
- array( 'old_text', 'old_flags' ),
- array( 'old_id' => $this->getTextId() ),
- __METHOD__ );
- }
- if( !$row && wfGetLB()->getServerCount() > 1 ) {
- // Possible slave lag!
- $dbw = wfGetDB( DB_MASTER );
- $row = $dbw->selectRow( 'text',
- array( 'old_text', 'old_flags' ),
- array( 'old_id' => $this->getTextId() ),
- __METHOD__ );
- }
- $text = self::getRevisionText( $row );
- # No negative caching -- negative hits on text rows may be due to corrupted slave servers
- if( $wgRevisionCacheExpiry && $text !== false ) {
- $wgMemc->set( $key, $text, $wgRevisionCacheExpiry );
- }
- wfProfileOut( __METHOD__ );
- return $text;
- }
- /**
- * Create a new null-revision for insertion into a page's
- * history. This will not re-save the text, but simply refer
- * to the text from the previous version.
- *
- * Such revisions can for instance identify page rename
- * operations and other such meta-modifications.
- *
- * @param Database $dbw
- * @param int $pageId ID number of the page to read from
- * @param string $summary
- * @param bool $minor
- * @return Revision
- */
- public static function newNullRevision( $dbw, $pageId, $summary, $minor ) {
- wfProfileIn( __METHOD__ );
- $current = $dbw->selectRow(
- array( 'page', 'revision' ),
- array( 'page_latest', 'rev_text_id', 'rev_len' ),
- array(
- 'page_id' => $pageId,
- 'page_latest=rev_id',
- ),
- __METHOD__ );
- if( $current ) {
- $revision = new Revision( array(
- 'page' => $pageId,
- 'comment' => $summary,
- 'minor_edit' => $minor,
- 'text_id' => $current->rev_text_id,
- 'parent_id' => $current->page_latest,
- 'len' => $current->rev_len
- ) );
- } else {
- $revision = null;
- }
- wfProfileOut( __METHOD__ );
- return $revision;
- }
- /**
- * Determine if the current user is allowed to view a particular
- * field of this revision, if it's marked as deleted.
- * @param int $field one of self::DELETED_TEXT,
- * self::DELETED_COMMENT,
- * self::DELETED_USER
- * @return bool
- */
- public function userCan( $field ) {
- if( ( $this->mDeleted & $field ) == $field ) {
- global $wgUser;
- $permission = ( $this->mDeleted & self::DELETED_RESTRICTED ) == self::DELETED_RESTRICTED
- ? 'suppressrevision'
- : 'deleterevision';
- wfDebug( "Checking for $permission due to $field match on $this->mDeleted\n" );
- return $wgUser->isAllowed( $permission );
- } else {
- return true;
- }
- }
- /**
- * Get rev_timestamp from rev_id, without loading the rest of the row
- * @param Title $title
- * @param integer $id
- */
- static function getTimestampFromId( $title, $id ) {
- $dbr = wfGetDB( DB_SLAVE );
- // Casting fix for DB2
- if ($id == '') {
- $id = 0;
- }
- $conds = array( 'rev_id' => $id );
- $conds['rev_page'] = $title->getArticleId();
- $timestamp = $dbr->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
- if ( $timestamp === false && wfGetLB()->getServerCount() > 1 ) {
- # Not in slave, try master
- $dbw = wfGetDB( DB_MASTER );
- $timestamp = $dbw->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
- }
- return wfTimestamp( TS_MW, $timestamp );
- }
- /**
- * Get count of revisions per page...not very efficient
- * @param Database $db
- * @param int $id, page id
- */
- static function countByPageId( $db, $id ) {
- $row = $db->selectRow( 'revision', 'COUNT(*) AS revCount',
- array( 'rev_page' => $id ), __METHOD__ );
- if( $row ) {
- return $row->revCount;
- }
- return 0;
- }
- /**
- * Get count of revisions per page...not very efficient
- * @param Database $db
- * @param Title $title
- */
- static function countByTitle( $db, $title ) {
- $id = $title->getArticleId();
- if( $id ) {
- return Revision::countByPageId( $db, $id );
- }
- return 0;
- }
- }
- /**
- * Aliases for backwards compatibility with 1.6
- */
- define( 'MW_REV_DELETED_TEXT', Revision::DELETED_TEXT );
- define( 'MW_REV_DELETED_COMMENT', Revision::DELETED_COMMENT );
- define( 'MW_REV_DELETED_USER', Revision::DELETED_USER );
- define( 'MW_REV_DELETED_RESTRICTED', Revision::DELETED_RESTRICTED );
|