8 require_once( 'Database.php' );
9 require_once( 'Article.php' );
17 * Load a page revision from a given revision ID number.
18 * Returns null if no such revision can be found.
24 function newFromId( $id ) {
25 return Revision
::newFromConds(
26 array( 'page_id=rev_page',
27 'rev_id' => IntVal( $id ) ) );
32 * Load either the current, or a specified, revision
33 * that's attached to a given title. If not attached
34 * to that title, will return null.
42 function newFromTitle( &$title, $id = 0 ) {
44 $matchId = IntVal( $id );
46 $matchId = 'page_latest';
48 return Revision
::newFromConds(
49 array( "rev_id=$matchId",
51 'page_namespace' => $title->getNamespace(),
52 'page_title' => $title->getDbkey() ) );
56 * Load either the current, or a specified, revision
57 * that's attached to a given page. If not attached
58 * to that page, will return null.
66 function loadFromPageId( &$db, $pageid, $id = 0 ) {
68 $matchId = IntVal( $id );
70 $matchId = 'page_latest';
72 $ret = Revision
::loadFromConds(
74 array( "rev_id=$matchId",
75 'rev_page' => IntVal( $pageid ),
76 'page_id=rev_page' ) );
81 * Load either the current, or a specified, revision
82 * that's attached to a given page. If not attached
83 * to that page, will return null.
91 function loadFromTitle( &$db, $title, $id = 0 ) {
93 $matchId = IntVal( $id );
95 $matchId = 'page_latest';
97 return Revision
::loadFromConds(
99 array( "rev_id=$matchId",
101 'page_namespace' => $title->getNamespace(),
102 'page_title' => $title->getDbkey() ) );
106 * Load the revision for the given title with the given timestamp.
107 * WARNING: Timestamps may in some circumstances not be unique,
108 * so this isn't the best key to use.
110 * @param Database $db
111 * @param Title $title
112 * @param string $timestamp
117 function loadFromTimestamp( &$db, &$title, $timestamp ) {
118 return Revision
::loadFromConds(
120 array( 'rev_timestamp' => $db->timestamp( $timestamp ),
122 'page_namespace' => $title->getNamespace(),
123 'page_title' => $title->getDbkey() ) );
127 * Given a set of conditions, fetch a revision.
129 * @param array $conditions
134 function newFromConds( $conditions ) {
135 $db =& wfGetDB( DB_SLAVE
);
136 $row = Revision
::loadFromConds( $db, $conditions );
137 if( is_null( $row ) ) {
138 $dbw =& wfGetDB( DB_MASTER
);
139 $row = Revision
::loadFromConds( $dbw, $conditions );
145 * Given a set of conditions, fetch a revision from
146 * the given database connection.
148 * @param Database $db
149 * @param array $conditions
154 function loadFromConds( &$db, $conditions ) {
155 $res = Revision
::fetchFromConds( $db, $conditions );
157 $row = $res->fetchObject();
160 $ret = new Revision( $row );
169 * Return a wrapper for a series of database rows to
170 * fetch all of a given page's revisions in turn.
171 * Each row can be fed to the constructor to get objects.
173 * @param Title $title
174 * @return ResultWrapper
178 function fetchAllRevisions( &$title ) {
179 return Revision
::fetchFromConds(
181 array( 'page_namespace' => $title->getNamespace(),
182 'page_title' => $title->getDbkey(),
183 'page_id=rev_page' ) );
187 * Return a wrapper for a series of database rows to
188 * fetch all of a given page's revisions in turn.
189 * Each row can be fed to the constructor to get objects.
191 * @param Title $title
192 * @return ResultWrapper
196 function fetchRevision( &$title ) {
197 return Revision
::fetchFromConds(
199 array( 'rev_id=page_latest',
200 'page_namespace' => $title->getNamespace(),
201 'page_title' => $title->getDbkey(),
202 'page_id=rev_page' ) );
206 * Given a set of conditions, return a ResultWrapper
207 * which will return matching database rows with the
208 * fields necessary to build Revision objects.
210 * @param Database $db
211 * @param array $conditions
212 * @return ResultWrapper
216 function fetchFromConds( &$db, $conditions ) {
218 array( 'page', 'revision' ),
219 array( 'page_namespace',
232 'Revision::fetchRow',
233 array( 'LIMIT' => 1 ) );
234 $ret = $db->resultObject( $res );
242 function Revision( $row ) {
243 if( is_object( $row ) ) {
244 $this->mId
= IntVal( $row->rev_id
);
245 $this->mPage
= IntVal( $row->rev_page
);
246 $this->mTextId
= IntVal( $row->rev_text_id
);
247 $this->mComment
= $row->rev_comment
;
248 $this->mUserText
= $row->rev_user_text
;
249 $this->mUser
= IntVal( $row->rev_user
);
250 $this->mMinorEdit
= IntVal( $row->rev_minor_edit
);
251 $this->mTimestamp
= $row->rev_timestamp
;
252 $this->mDeleted
= IntVal( $row->rev_deleted
);
254 $this->mCurrent
= ( $row->rev_id
== $row->page_latest
);
255 $this->mTitle
= Title
::makeTitle( $row->page_namespace
,
258 if( isset( $row->old_text
) ) {
259 $this->mText
= $this->getRevisionText( $row );
263 } elseif( is_array( $row ) ) {
264 // Build a new revision to be saved...
267 $this->mId
= isset( $row['id'] ) ?
IntVal( $row['id'] ) : null;
268 $this->mPage
= isset( $row['page'] ) ?
IntVal( $row['page'] ) : null;
269 $this->mTextId
= isset( $row['text_id'] ) ?
IntVal( $row['text_id'] ) : null;
270 $this->mUserText
= isset( $row['user_text'] ) ?
StrVal( $row['user_text'] ) : $wgUser->getName();
271 $this->mUser
= isset( $row['user'] ) ?
IntVal( $row['user'] ) : $wgUser->getId();
272 $this->mMinorEdit
= isset( $row['minor_edit'] ) ?
IntVal( $row['minor_edit'] ) : 0;
273 $this->mTimestamp
= isset( $row['timestamp'] ) ?
StrVal( $row['timestamp'] ) : wfTimestamp( TS_MW
);
274 $this->mDeleted
= isset( $row['deleted'] ) ?
IntVal( $row['deleted'] ) : 0;
276 // Enforce spacing trimming on supplied text
277 $this->mComment
= isset( $row['comment'] ) ?
trim( StrVal( $row['comment'] ) ) : null;
278 $this->mText
= isset( $row['text'] ) ?
rtrim( StrVal( $row['text'] ) ) : null;
280 $this->mTitle
= null; # Load on demand if needed
281 $this->mCurrent
= false;
283 wfDebugDieBacktrace( 'Revision constructor passed invalid row format.' );
301 function getTextId() {
302 return $this->mTextId
;
306 * Returns the title of the page associated with this entry.
309 function getTitle() {
310 if( isset( $this->mTitle
) ) {
311 return $this->mTitle
;
313 $dbr =& wfGetDB( DB_SLAVE
);
314 $row = $dbr->selectRow(
315 array( 'page', 'revision' ),
316 array( 'page_namespace', 'page_title' ),
317 array( 'page_id=rev_page',
318 'rev_id' => $this->mId
),
319 'Revision::getTItle' );
321 $this->mTitle
= Title
::makeTitle( $row->page_namespace
,
324 return $this->mTitle
;
344 function getUserText() {
345 return $this->mUserText
;
351 function getComment() {
352 return $this->mComment
;
359 return (bool)$this->mMinorEdit
;
365 function isDeleted() {
366 return (bool)$this->mDeleted
;
373 if( is_null( $this->mText
) ) {
374 // Revision text is immutable. Load on demand:
375 $this->mText
= $this->loadText();
383 function getTimestamp() {
384 return wfTimestamp(TS_MW
, $this->mTimestamp
);
390 function isCurrent() {
391 return $this->mCurrent
;
397 function getPrevious() {
398 $prev = $this->mTitle
->getPreviousRevisionID( $this->mId
);
399 return Revision
::newFromTitle( $this->mTitle
, $prev );
406 $next = $this->mTitle
->getNextRevisionID( $this->mId
);
407 return Revision
::newFromTitle( $this->mTitle
, $next );
412 * Get revision text associated with an old or archive row
413 * $row is usually an object from wfFetchRow(), both the flags and the text
414 * field must be included
416 * @param integer $row Id of a row
417 * @param string $prefix table prefix (default 'old_')
418 * @return string $text|false the text requested
420 function getRevisionText( $row, $prefix = 'old_' ) {
421 $fname = 'Revision::getRevisionText';
422 wfProfileIn( $fname );
425 $textField = $prefix . 'text';
426 $flagsField = $prefix . 'flags';
428 if( isset( $row->$flagsField ) ) {
429 $flags = explode( ',', $row->$flagsField );
434 if( isset( $row->$textField ) ) {
435 $text = $row->$textField;
437 wfProfileOut( $fname );
441 # Use external methods for external objects, text in table is URL-only then
442 if ( in_array( 'external', $flags ) ) {
444 @list
($proto,$path)=explode('://',$url,2);
446 wfProfileOut( $fname );
449 require_once('ExternalStore.php');
450 $text=ExternalStore
::fetchFromURL($url);
453 if( in_array( 'gzip', $flags ) ) {
454 # Deal with optional compression of archived pages.
455 # This can be done periodically via maintenance/compressOld.php, and
456 # as pages are saved if $wgCompressRevisions is set.
457 $text = gzinflate( $text );
460 if( in_array( 'object', $flags ) ) {
461 # Generic compressed storage
462 $obj = unserialize( $text );
464 # Bugger, corrupted my test database by double-serializing
465 if ( !is_object( $obj ) ) {
466 $obj = unserialize( $obj );
469 $text = $obj->getText();
472 global $wgLegacyEncoding;
473 if( $wgLegacyEncoding && !in_array( 'utf-8', $flags ) ) {
474 # Old revisions kept around in a legacy encoding?
475 # Upconvert on demand.
476 global $wgInputEncoding, $wgContLang;
477 $text = $wgContLang->iconv( $wgLegacyEncoding, $wgInputEncoding, $text );
479 wfProfileOut( $fname );
484 * If $wgCompressRevisions is enabled, we will compress data.
485 * The input string is modified in place.
486 * Return value is the flags field: contains 'gzip' if the
487 * data is compressed, and 'utf-8' if we're saving in UTF-8
491 * @param mixed $text reference to a text
494 function compressRevisionText( &$text ) {
495 global $wgCompressRevisions;
498 # Revisions not marked this way will be converted
499 # on load if $wgLegacyCharset is set in the future.
502 if( $wgCompressRevisions ) {
503 if( function_exists( 'gzdeflate' ) ) {
504 $text = gzdeflate( $text );
507 wfDebug( "Revision::compressRevisionText() -- no zlib support, not compressing\n" );
510 return implode( ',', $flags );
514 * Insert a new revision into the database, returning the new revision ID
515 * number on success and dies horribly on failure.
517 * @param Database $dbw
520 function insertOn( &$dbw ) {
521 $fname = 'Revision::insertOn';
522 wfProfileIn( $fname );
524 $mungedText = $this->mText
;
525 $flags = Revision
::compressRevisionText( $mungedText );
527 # Record the text to the text table
528 if( !isset( $this->mTextId
) ) {
529 $old_id = $dbw->nextSequenceValue( 'text_old_id_val' );
530 $dbw->insert( 'text',
533 'old_text' => $mungedText,
534 'old_flags' => $flags,
537 $this->mTextId
= $dbw->insertId();
540 # Record the edit in revisions
541 $rev_id = isset( $this->mId
)
543 : $dbw->nextSequenceValue( 'rev_rev_id_val' );
544 $dbw->insert( 'revision',
547 'rev_page' => $this->mPage
,
548 'rev_text_id' => $this->mTextId
,
549 'rev_comment' => $this->mComment
,
550 'rev_minor_edit' => $this->mMinorEdit ?
1 : 0,
551 'rev_user' => $this->mUser
,
552 'rev_user_text' => $this->mUserText
,
553 'rev_timestamp' => $dbw->timestamp( $this->mTimestamp
),
554 'rev_deleted' => $this->mDeleted
,
558 $this->mId
= !is_null($rev_id) ?
$rev_id : $dbw->insertId();
560 wfProfileOut( $fname );
565 * Lazy-load the revision's text.
566 * Currently hardcoded to the 'text' table storage engine.
571 function loadText() {
572 $fname = 'Revision::loadText';
573 wfProfileIn( $fname );
575 $dbr =& wfGetDB( DB_SLAVE
);
576 $row = $dbr->selectRow( 'text',
577 array( 'old_text', 'old_flags' ),
578 array( 'old_id' => $this->getTextId() ),
582 $dbw =& wfGetDB( DB_MASTER
);
583 $row = $dbw->selectRow( 'text',
584 array( 'old_text', 'old_flags' ),
585 array( 'old_id' => $this->getTextId() ),
589 $text = Revision
::getRevisionText( $row );
590 wfProfileOut( $fname );
596 * Create a new null-revision for insertion into a page's
597 * history. This will not re-save the text, but simply refer
598 * to the text from the previous version.
600 * Such revisions can for instance identify page rename
601 * operations and other such meta-modifications.
603 * @param Database $dbw
604 * @param int $pageId ID number of the page to read from
605 * @param string $summary
609 function newNullRevision( &$dbw, $pageId, $summary, $minor ) {
610 $fname = 'Revision::newNullRevision';
611 wfProfileIn( $fname );
613 $current = $dbw->selectRow(
614 array( 'page', 'revision' ),
615 array( 'page_latest', 'rev_text_id' ),
617 'page_id' => $pageId,
618 'page_latest=rev_id',
623 $revision = new Revision( array(
625 'comment' => $summary,
626 'minor_edit' => $minor,
627 'text_id' => $current->rev_text_id
,
633 wfProfileOut( $fname );