MediaWiki  master
PageArchive.php
Go to the documentation of this file.
1 <?php
21 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
25 use Wikimedia\Assert\Assert;
28 
32 class PageArchive {
33  use ProtectedHookAccessorTrait;
34 
36  protected $title;
37 
39  protected $fileStatus;
40 
42  protected $revisionStatus;
43 
45  protected $config;
46 
47  public function __construct( $title, Config $config = null ) {
48  if ( $title === null ) {
49  throw new MWException( __METHOD__ . ' given a null title.' );
50  }
51  $this->title = $title;
52  if ( $config === null ) {
53  wfDebug( __METHOD__ . ' did not have a Config object passed to it' );
54  $config = MediaWikiServices::getInstance()->getMainConfig();
55  }
56  $this->config = $config;
57  }
58 
62  private function getRevisionStore() {
63  // TODO: Refactor: delete()/undeleteAsUser() should live in a PageStore service;
64  // Methods in PageArchive and RevisionStore that deal with archive revisions
65  // should move into an ArchiveStore service (but could still be implemented
66  // together with RevisionStore).
67  return MediaWikiServices::getInstance()->getRevisionStore();
68  }
69 
70  public function doesWrites() {
71  return true;
72  }
73 
82  public static function listPagesBySearch( $term ) {
83  $title = Title::newFromText( $term );
84  if ( $title ) {
85  $ns = $title->getNamespace();
86  $termMain = $title->getText();
87  $termDb = $title->getDBkey();
88  } else {
89  // Prolly won't work too good
90  // @todo handle bare namespace names cleanly?
91  $ns = 0;
92  $termMain = $termDb = $term;
93  }
94 
95  // Try search engine first
96  $engine = MediaWikiServices::getInstance()->newSearchEngine();
97  $engine->setLimitOffset( 100 );
98  $engine->setNamespaces( [ $ns ] );
99  $results = $engine->searchArchiveTitle( $termMain );
100  if ( !$results->isOK() ) {
101  $results = [];
102  } else {
103  $results = $results->getValue();
104  }
105 
106  if ( !$results ) {
107  // Fall back to regular prefix search
108  return self::listPagesByPrefix( $term );
109  }
110 
111  $dbr = wfGetDB( DB_REPLICA );
112  $condTitles = array_unique( array_map( function ( Title $t ) {
113  return $t->getDBkey();
114  }, $results ) );
115  $conds = [
116  'ar_namespace' => $ns,
117  $dbr->makeList( [ 'ar_title' => $condTitles ], LIST_OR ) . " OR ar_title " .
118  $dbr->buildLike( $termDb, $dbr->anyString() )
119  ];
120 
121  return self::listPages( $dbr, $conds );
122  }
123 
132  public static function listPagesByPrefix( $prefix ) {
133  $dbr = wfGetDB( DB_REPLICA );
134 
135  $title = Title::newFromText( $prefix );
136  if ( $title ) {
137  $ns = $title->getNamespace();
138  $prefix = $title->getDBkey();
139  } else {
140  // Prolly won't work too good
141  // @todo handle bare namespace names cleanly?
142  $ns = 0;
143  }
144 
145  $conds = [
146  'ar_namespace' => $ns,
147  'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
148  ];
149 
150  return self::listPages( $dbr, $conds );
151  }
152 
158  protected static function listPages( $dbr, $condition ) {
159  return $dbr->select(
160  [ 'archive' ],
161  [
162  'ar_namespace',
163  'ar_title',
164  'count' => 'COUNT(*)'
165  ],
166  $condition,
167  __METHOD__,
168  [
169  'GROUP BY' => [ 'ar_namespace', 'ar_title' ],
170  'ORDER BY' => [ 'ar_namespace', 'ar_title' ],
171  'LIMIT' => 100,
172  ]
173  );
174  }
175 
182  public function listRevisions() {
183  $revisionStore = $this->getRevisionStore();
184  $queryInfo = $revisionStore->getArchiveQueryInfo();
185 
186  $conds = [
187  'ar_namespace' => $this->title->getNamespace(),
188  'ar_title' => $this->title->getDBkey(),
189  ];
190 
191  // NOTE: ordering by ar_timestamp and ar_id, to remove ambiguity.
192  // XXX: Ideally, we would be ordering by ar_timestamp and ar_rev_id, but since we
193  // don't have an index on ar_rev_id, that causes a file sort.
194  $options = [ 'ORDER BY' => [ 'ar_timestamp DESC', 'ar_id DESC' ] ];
195 
197  $queryInfo['tables'],
198  $queryInfo['fields'],
199  $conds,
200  $queryInfo['joins'],
201  $options,
202  ''
203  );
204 
205  $dbr = wfGetDB( DB_REPLICA );
206  return $dbr->select(
207  $queryInfo['tables'],
208  $queryInfo['fields'],
209  $conds,
210  __METHOD__,
211  $options,
212  $queryInfo['joins']
213  );
214  }
215 
224  public function listFiles() {
225  if ( $this->title->getNamespace() !== NS_FILE ) {
226  return null;
227  }
228 
229  $dbr = wfGetDB( DB_REPLICA );
230  $fileQuery = ArchivedFile::getQueryInfo();
231  return $dbr->select(
232  $fileQuery['tables'],
233  $fileQuery['fields'],
234  [ 'fa_name' => $this->title->getDBkey() ],
235  __METHOD__,
236  [ 'ORDER BY' => 'fa_timestamp DESC' ],
237  $fileQuery['joins']
238  );
239  }
240 
250  public function getRevision( $timestamp ) {
251  wfDeprecated( __METHOD__, '1.32' );
252  $revRecord = $this->getRevisionRecordByTimestamp( $timestamp );
253  return $revRecord ? new Revision( $revRecord ) : null;
254  }
255 
264  public function getRevisionRecordByTimestamp( $timestamp ) {
265  $dbr = wfGetDB( DB_REPLICA );
266  $rec = $this->getRevisionByConditions(
267  [ 'ar_timestamp' => $dbr->timestamp( $timestamp ) ]
268  );
269  return $rec;
270  }
271 
280  public function getArchivedRevision( $revId ) {
281  wfDeprecated( __METHOD__, '1.35' );
282 
283  // Protect against code switching from getRevision() passing in a timestamp.
284  Assert::parameterType( 'integer', $revId, '$revId' );
285 
286  $revRecord = $this->getArchivedRevisionRecord( $revId );
287  return $revRecord ? new Revision( $revRecord ) : null;
288  }
289 
298  public function getArchivedRevisionRecord( int $revId ) {
299  return $this->getRevisionByConditions( [ 'ar_rev_id' => $revId ] );
300  }
301 
308  private function getRevisionByConditions( array $conditions, array $options = [] ) {
309  $dbr = wfGetDB( DB_REPLICA );
310  $arQuery = $this->getRevisionStore()->getArchiveQueryInfo();
311 
312  $conditions += [
313  'ar_namespace' => $this->title->getNamespace(),
314  'ar_title' => $this->title->getDBkey(),
315  ];
316 
317  $row = $dbr->selectRow(
318  $arQuery['tables'],
319  $arQuery['fields'],
320  $conditions,
321  __METHOD__,
322  $options,
323  $arQuery['joins']
324  );
325 
326  if ( $row ) {
327  return $this->getRevisionStore()->newRevisionFromArchiveRow( $row, 0, $this->title );
328  }
329 
330  return null;
331  }
332 
345  public function getPreviousRevision( $timestamp ) {
346  wfDeprecated( __METHOD__, '1.35' );
347 
348  $revRecord = $this->getPreviousRevisionRecord( $timestamp );
349  $rev = $revRecord ? new Revision( $revRecord ) : null;
350  return $rev;
351  }
352 
365  public function getPreviousRevisionRecord( string $timestamp ) {
366  $dbr = wfGetDB( DB_REPLICA );
367 
368  // Check the previous deleted revision...
369  $row = $dbr->selectRow( 'archive',
370  [ 'ar_rev_id', 'ar_timestamp' ],
371  [ 'ar_namespace' => $this->title->getNamespace(),
372  'ar_title' => $this->title->getDBkey(),
373  'ar_timestamp < ' .
374  $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ],
375  __METHOD__,
376  [
377  'ORDER BY' => 'ar_timestamp DESC',
378  'LIMIT' => 1 ] );
379  $prevDeleted = $row ? wfTimestamp( TS_MW, $row->ar_timestamp ) : false;
380  $prevDeletedId = $row ? intval( $row->ar_rev_id ) : null;
381 
382  $row = $dbr->selectRow( [ 'page', 'revision' ],
383  [ 'rev_id', 'rev_timestamp' ],
384  [
385  'page_namespace' => $this->title->getNamespace(),
386  'page_title' => $this->title->getDBkey(),
387  'page_id = rev_page',
388  'rev_timestamp < ' .
389  $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ],
390  __METHOD__,
391  [
392  'ORDER BY' => 'rev_timestamp DESC',
393  'LIMIT' => 1 ] );
394  $prevLive = $row ? wfTimestamp( TS_MW, $row->rev_timestamp ) : false;
395  $prevLiveId = $row ? intval( $row->rev_id ) : null;
396 
397  if ( $prevLive && $prevLive > $prevDeleted ) {
398  // Most prior revision was live
399  $rec = $this->getRevisionStore()->getRevisionById( $prevLiveId );
400  } elseif ( $prevDeleted ) {
401  // Most prior revision was deleted
402  $rec = $this->getArchivedRevisionRecord( $prevDeletedId );
403  } else {
404  $rec = null;
405  }
406 
407  return $rec;
408  }
409 
415  public function getLastRevisionId() {
416  $dbr = wfGetDB( DB_REPLICA );
417  $revId = $dbr->selectField(
418  'archive',
419  'ar_rev_id',
420  [ 'ar_namespace' => $this->title->getNamespace(),
421  'ar_title' => $this->title->getDBkey() ],
422  __METHOD__,
423  [ 'ORDER BY' => [ 'ar_timestamp DESC', 'ar_id DESC' ] ]
424  );
425 
426  return $revId ? intval( $revId ) : false;
427  }
428 
435  public function isDeleted() {
436  $dbr = wfGetDB( DB_REPLICA );
437  $row = $dbr->selectRow(
438  [ 'archive' ],
439  '1', // We don't care about the value. Allow the database to optimize.
440  [ 'ar_namespace' => $this->title->getNamespace(),
441  'ar_title' => $this->title->getDBkey() ],
442  __METHOD__
443  );
444 
445  return (bool)$row;
446  }
447 
469  public function undeleteAsUser(
470  $timestamps,
471  User $user,
472  $comment = '',
473  $fileVersions = [],
474  $unsuppress = false,
475  $tags = null
476  ) {
477  // If both the set of text revisions and file revisions are empty,
478  // restore everything. Otherwise, just restore the requested items.
479  $restoreAll = empty( $timestamps ) && empty( $fileVersions );
480 
481  $restoreText = $restoreAll || !empty( $timestamps );
482  $restoreFiles = $restoreAll || !empty( $fileVersions );
483 
484  if ( $restoreFiles && $this->title->getNamespace() === NS_FILE ) {
486  $img = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
487  ->newFile( $this->title );
488  $img->load( File::READ_LATEST );
489  $this->fileStatus = $img->restore( $fileVersions, $unsuppress );
490  if ( !$this->fileStatus->isOK() ) {
491  return false;
492  }
493  $filesRestored = $this->fileStatus->successCount;
494  } else {
495  $filesRestored = 0;
496  }
497 
498  if ( $restoreText ) {
499  $this->revisionStatus = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
500  if ( !$this->revisionStatus->isOK() ) {
501  return false;
502  }
503 
504  $textRestored = $this->revisionStatus->getValue();
505  } else {
506  $textRestored = 0;
507  }
508 
509  // Touch the log!
510 
511  if ( !$textRestored && !$filesRestored ) {
512  wfDebug( "Undelete: nothing undeleted..." );
513 
514  return false;
515  }
516 
517  $logEntry = new ManualLogEntry( 'delete', 'restore' );
518  $logEntry->setPerformer( $user );
519  $logEntry->setTarget( $this->title );
520  $logEntry->setComment( $comment );
521  $logEntry->addTags( $tags );
522  $logEntry->setParameters( [
523  ':assoc:count' => [
524  'revisions' => $textRestored,
525  'files' => $filesRestored,
526  ],
527  ] );
528 
529  $this->getHookRunner()->onArticleUndeleteLogEntry( $this, $logEntry, $user );
530 
531  $logid = $logEntry->insert();
532  $logEntry->publish( $logid );
533 
534  return [ $textRestored, $filesRestored, $comment ];
535  }
536 
548  private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) {
549  if ( wfReadOnly() ) {
550  throw new ReadOnlyError();
551  }
552 
553  $dbw = wfGetDB( DB_MASTER );
554  $dbw->startAtomic( __METHOD__ );
555 
556  $restoreAll = empty( $timestamps );
557 
558  # Does this page already exist? We'll have to update it...
559  $article = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $this->title );
560  # Load latest data for the current page (T33179)
561  $article->loadPageData( 'fromdbmaster' );
562  $oldcountable = $article->isCountable();
563 
564  if ( $article->exists() ) {
565  # Page already exists. Import the history, and if necessary
566  # we'll update the latest revision field in the record.
567  $makepage = false;
568 
569  $page = $dbw->selectRow( 'page',
570  [ 'page_id', 'page_latest' ],
571  [ 'page_namespace' => $this->title->getNamespace(),
572  'page_title' => $this->title->getDBkey() ],
573  __METHOD__,
574  [ 'FOR UPDATE' ] // lock page for WikiPage::updateRevisionOn call
575  );
576 
577  # Get the time span of this page
578  $previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
579  [ 'rev_id' => $page->page_latest ],
580  __METHOD__ );
581 
582  if ( $previousTimestamp === false ) {
583  wfDebug( __METHOD__ . ": existing page refers to a page_latest that does not exist" );
584 
585  $status = Status::newGood( 0 );
586  $status->warning( 'undeleterevision-missing' );
587  $dbw->endAtomic( __METHOD__ );
588 
589  return $status;
590  }
591  } else {
592  # Have to create a new article...
593  $makepage = true;
594  $previousTimestamp = 0;
595  }
596 
597  $oldWhere = [
598  'ar_namespace' => $this->title->getNamespace(),
599  'ar_title' => $this->title->getDBkey(),
600  ];
601  if ( !$restoreAll ) {
602  $oldWhere['ar_timestamp'] = array_map( [ &$dbw, 'timestamp' ], $timestamps );
603  }
604 
605  $revisionStore = $this->getRevisionStore();
606  $queryInfo = $revisionStore->getArchiveQueryInfo();
607  $queryInfo['tables'][] = 'revision';
608  $queryInfo['fields'][] = 'rev_id';
609  $queryInfo['joins']['revision'] = [ 'LEFT JOIN', 'ar_rev_id=rev_id' ];
610 
614  $result = $dbw->select(
615  $queryInfo['tables'],
616  $queryInfo['fields'],
617  $oldWhere,
618  __METHOD__,
619  /* options */
620  [ 'ORDER BY' => 'ar_timestamp' ],
621  $queryInfo['joins']
622  );
623 
624  $rev_count = $result->numRows();
625  if ( !$rev_count ) {
626  wfDebug( __METHOD__ . ": no revisions to restore" );
627 
628  $status = Status::newGood( 0 );
629  $status->warning( "undelete-no-results" );
630  $dbw->endAtomic( __METHOD__ );
631 
632  return $status;
633  }
634 
635  // We use ar_id because there can be duplicate ar_rev_id even for the same
636  // page. In this case, we may be able to restore the first one.
637  $restoreFailedArIds = [];
638 
639  // Map rev_id to the ar_id that is allowed to use it. When checking later,
640  // if it doesn't match, the current ar_id can not be restored.
641 
642  // Value can be an ar_id or -1 (-1 means no ar_id can use it, since the
643  // rev_id is taken before we even start the restore).
644  $allowedRevIdToArIdMap = [];
645 
646  $latestRestorableRow = null;
647 
648  foreach ( $result as $row ) {
649  if ( $row->ar_rev_id ) {
650  // rev_id is taken even before we start restoring.
651  if ( $row->ar_rev_id === $row->rev_id ) {
652  $restoreFailedArIds[] = $row->ar_id;
653  $allowedRevIdToArIdMap[$row->ar_rev_id] = -1;
654  } else {
655  // rev_id is not taken yet in the DB, but it might be taken
656  // by a prior revision in the same restore operation. If
657  // not, we need to reserve it.
658  if ( isset( $allowedRevIdToArIdMap[$row->ar_rev_id] ) ) {
659  $restoreFailedArIds[] = $row->ar_id;
660  } else {
661  $allowedRevIdToArIdMap[$row->ar_rev_id] = $row->ar_id;
662  $latestRestorableRow = $row;
663  }
664  }
665  } else {
666  // If ar_rev_id is null, there can't be a collision, and a
667  // rev_id will be chosen automatically.
668  $latestRestorableRow = $row;
669  }
670  }
671 
672  $result->seek( 0 ); // move back
673 
674  $oldPageId = 0;
675  if ( $latestRestorableRow !== null ) {
676  $oldPageId = (int)$latestRestorableRow->ar_page_id; // pass this to ArticleUndelete hook
677 
678  // Grab the content to check consistency with global state before restoring the page.
679  // XXX: The only current use case is Wikibase, which tries to enforce uniqueness of
680  // certain things across all pages. There may be a better way to do that.
681  $revision = $revisionStore->newRevisionFromArchiveRow(
682  $latestRestorableRow,
683  0,
684  $this->title
685  );
686 
687  // TODO: use User::newFromUserIdentity from If610c68f4912e
688  // TODO: The User isn't used for anything in prepareSave()! We should drop it.
689  $user = User::newFromName( $revision->getUser( RevisionRecord::RAW )->getName(), false );
690 
691  foreach ( $revision->getSlotRoles() as $role ) {
692  $content = $revision->getContent( $role, RevisionRecord::RAW );
693 
694  // NOTE: article ID may not be known yet. prepareSave() should not modify the database.
695  $status = $content->prepareSave( $article, 0, -1, $user );
696  if ( !$status->isOK() ) {
697  $dbw->endAtomic( __METHOD__ );
698 
699  return $status;
700  }
701  }
702  }
703 
704  $newid = false; // newly created page ID
705  $restored = 0; // number of revisions restored
707  $revision = null;
708  $restoredPages = [];
709  // If there are no restorable revisions, we can skip most of the steps.
710  if ( $latestRestorableRow === null ) {
711  $failedRevisionCount = $rev_count;
712  } else {
713  if ( $makepage ) {
714  // Check the state of the newest to-be version...
715  if ( !$unsuppress
716  && ( $latestRestorableRow->ar_deleted & RevisionRecord::DELETED_TEXT )
717  ) {
718  $dbw->endAtomic( __METHOD__ );
719 
720  return Status::newFatal( "undeleterevdel" );
721  }
722  // Safe to insert now...
723  $newid = $article->insertOn( $dbw, $latestRestorableRow->ar_page_id );
724  if ( $newid === false ) {
725  // The old ID is reserved; let's pick another
726  $newid = $article->insertOn( $dbw );
727  }
728  $pageId = $newid;
729  } else {
730  // Check if a deleted revision will become the current revision...
731  if ( $latestRestorableRow->ar_timestamp > $previousTimestamp ) {
732  // Check the state of the newest to-be version...
733  if ( !$unsuppress
734  && ( $latestRestorableRow->ar_deleted & RevisionRecord::DELETED_TEXT )
735  ) {
736  $dbw->endAtomic( __METHOD__ );
737 
738  return Status::newFatal( "undeleterevdel" );
739  }
740  }
741 
742  $newid = false;
743  $pageId = $article->getId();
744  }
745 
746  foreach ( $result as $row ) {
747  // Check for key dupes due to needed archive integrity.
748  if ( $row->ar_rev_id && $allowedRevIdToArIdMap[$row->ar_rev_id] !== $row->ar_id ) {
749  continue;
750  }
751  // Insert one revision at a time...maintaining deletion status
752  // unless we are specifically removing all restrictions...
753  $revision = $revisionStore->newRevisionFromArchiveRow(
754  $row,
755  0,
756  $this->title,
757  [
758  'page_id' => $pageId,
759  'deleted' => $unsuppress ? 0 : $row->ar_deleted
760  ]
761  );
762 
763  // This will also copy the revision to ip_changes if it was an IP edit.
764  $revisionStore->insertRevisionOn( $revision, $dbw );
765 
766  $restored++;
767 
768  $hookRunner = $this->getHookRunner();
769  $hookRunner->onRevisionUndeleted( $revision, $row->ar_page_id );
770 
771  // Hook is hard deprecated since 1.35
772  if ( $this->getHookContainer()->isRegistered( 'ArticleRevisionUndeleted' ) ) {
773  // Only create the Revision object if it is needed
774  $legacyRevision = new Revision( $revision );
775  $hookRunner->onArticleRevisionUndeleted(
776  $this->title,
777  $legacyRevision,
778  $row->ar_page_id
779  );
780  }
781  $restoredPages[$row->ar_page_id] = true;
782  }
783 
784  // Now that it's safely stored, take it out of the archive
785  // Don't delete rows that we failed to restore
786  $toDeleteConds = $oldWhere;
787  $failedRevisionCount = count( $restoreFailedArIds );
788  if ( $failedRevisionCount > 0 ) {
789  $toDeleteConds[] = 'ar_id NOT IN ( ' . $dbw->makeList( $restoreFailedArIds ) . ' )';
790  }
791 
792  $dbw->delete( 'archive',
793  $toDeleteConds,
794  __METHOD__ );
795  }
796 
797  $status = Status::newGood( $restored );
798 
799  if ( $failedRevisionCount > 0 ) {
800  $status->warning(
801  wfMessage( 'undeleterevision-duplicate-revid', $failedRevisionCount ) );
802  }
803 
804  // Was anything restored at all?
805  if ( $restored ) {
806  $created = (bool)$newid;
807 
808  $latestRevId = $article->getLatest();
809  if ( $latestRevId ) {
810  // If not found (false), cast to 0 so that the page is updated
811  // Just to be on the safe side, even though it should always be found
812  $latestRevTimestamp = (int)$revisionStore->getTimestampFromId(
813  $latestRevId,
814  RevisionStore::READ_LATEST
815  );
816  } else {
817  $latestRevTimestamp = 0;
818  }
819 
820  if ( $revision->getTimestamp() > $latestRevTimestamp ) {
821  // Attach the latest revision to the page...
822  // XXX: updateRevisionOn should probably move into a PageStore service.
823  $wasnew = $article->updateRevisionOn(
824  $dbw,
825  $revision,
826  $latestRevId
827  );
828  } else {
829  $wasnew = false;
830  }
831 
832  if ( $created || $wasnew ) {
833  // Update site stats, link tables, etc
834  // TODO: use DerivedPageDataUpdater from If610c68f4912e!
835  $article->doEditUpdates(
836  $revision,
837  User::newFromName( $revision->getUser( RevisionRecord::RAW )->getName(), false ),
838  [
839  'created' => $created,
840  'oldcountable' => $oldcountable,
841  'restored' => true
842  ]
843  );
844  }
845 
846  $this->getHookRunner()->onArticleUndelete(
847  $this->title, $created, $comment, $oldPageId, $restoredPages );
848 
849  if ( $this->title->getNamespace() === NS_FILE ) {
851  $this->title,
852  'imagelinks',
853  [ 'causeAction' => 'file-restore' ]
854  );
855  JobQueueGroup::singleton()->lazyPush( $job );
856  }
857  }
858 
859  $dbw->endAtomic( __METHOD__ );
860 
861  return $status;
862  }
863 
867  public function getFileStatus() {
868  return $this->fileStatus;
869  }
870 
874  public function getRevisionStatus() {
875  return $this->revisionStatus;
876  }
877 }
ReadOnlyError
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Definition: ReadOnlyError.php:29
PageArchive\getRevisionRecordByTimestamp
getRevisionRecordByTimestamp( $timestamp)
Return a RevisionRecord object containing data for the deleted revision.
Definition: PageArchive.php:264
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:328
PageArchive\getFileStatus
getFileStatus()
Definition: PageArchive.php:867
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:46
StatusValue\newFatal
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:70
PageArchive
Used to show archived pages and eventually restore them.
Definition: PageArchive.php:32
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:165
PageArchive\undeleteAsUser
undeleteAsUser( $timestamps, User $user, $comment='', $fileVersions=[], $unsuppress=false, $tags=null)
Restore the given (or all) text and file revisions for the page.
Definition: PageArchive.php:469
Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:80
PageArchive\listPages
static listPages( $dbr, $condition)
Definition: PageArchive.php:158
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1815
PageArchive\$config
Config $config
Definition: PageArchive.php:45
PageArchive\listPagesByPrefix
static listPagesByPrefix( $prefix)
List deleted pages recorded in the archive table matching the given title prefix.
Definition: PageArchive.php:132
NS_FILE
const NS_FILE
Definition: Defines.php:75
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1126
User\newFromName
static newFromName( $name, $validate='valid')
Definition: User.php:545
ArchivedFile\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archivedfile object.
Definition: ArchivedFile.php:234
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1220
PageArchive\listFiles
listFiles()
List the deleted file revisions for this page, if it's a file page.
Definition: PageArchive.php:224
PageArchive\$revisionStatus
Status $revisionStatus
Definition: PageArchive.php:42
PageArchive\listPagesBySearch
static listPagesBySearch( $term)
List deleted pages recorded in the archive matching the given term, using search engine archive.
Definition: PageArchive.php:82
HTMLCacheUpdateJob\newForBacklinks
static newForBacklinks(Title $title, $table, $params=[])
Definition: HTMLCacheUpdateJob.php:59
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
PageArchive\isDeleted
isDeleted()
Quick check if any archived revisions are present for the page.
Definition: PageArchive.php:435
PageArchive\getRevisionStore
getRevisionStore()
Definition: PageArchive.php:62
$dbr
$dbr
Definition: testCompression.php:54
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:44
PageArchive\getArchivedRevisionRecord
getArchivedRevisionRecord(int $revId)
Return the archived revision with the given ID.
Definition: PageArchive.php:298
Revision
Definition: Revision.php:40
ChangeTags\modifyDisplayQuery
static modifyDisplayQuery(&$tables, &$fields, &$conds, &$join_conds, &$options, $filter_tag='')
Applies all tags-related changes to a query.
Definition: ChangeTags.php:851
Config
Interface for configuration instances.
Definition: Config.php:30
LIST_OR
const LIST_OR
Definition: Defines.php:51
Title\getDBkey
getDBkey()
Get the main part with underscores.
Definition: Title.php:1025
MWException
MediaWiki exception.
Definition: MWException.php:29
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1027
Wikimedia\Rdbms\IResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: IResultWrapper.php:24
Title\getNamespace
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:1034
PageArchive\undeleteRevisions
undeleteRevisions( $timestamps, $unsuppress=false, $comment='')
This is the meaty bit – It restores archived revisions of the given page to the revision table.
Definition: PageArchive.php:548
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2448
PageArchive\listRevisions
listRevisions()
List the revisions of the given page.
Definition: PageArchive.php:182
PageArchive\getPreviousRevisionRecord
getPreviousRevisionRecord(string $timestamp)
Return the most-previous revision, either live or deleted, against the deleted revision given by time...
Definition: PageArchive.php:365
PageArchive\getRevisionStatus
getRevisionStatus()
Definition: PageArchive.php:874
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
DB_MASTER
const DB_MASTER
Definition: defines.php:26
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:910
PageArchive\$fileStatus
Status $fileStatus
Definition: PageArchive.php:39
PageArchive\getLastRevisionId
getLastRevisionId()
Returns the ID of the latest deleted revision.
Definition: PageArchive.php:415
$content
$content
Definition: router.php:76
PageArchive\getRevision
getRevision( $timestamp)
Return a Revision object containing data for the deleted revision.
Definition: PageArchive.php:250
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
PageArchive\getArchivedRevision
getArchivedRevision( $revId)
Return the archived revision with the given ID.
Definition: PageArchive.php:280
PageArchive\doesWrites
doesWrites()
Definition: PageArchive.php:70
PageArchive\getRevisionByConditions
getRevisionByConditions(array $conditions, array $options=[])
Definition: PageArchive.php:308
Title
Represents a title within MediaWiki.
Definition: Title.php:41
JobQueueGroup\singleton
static singleton( $domain=false)
Definition: JobQueueGroup.php:70
$job
if(count( $args)< 1) $job
Definition: recompressTracked.php:50
ManualLogEntry
Class for creating new log entries and inserting them into the database.
Definition: ManualLogEntry.php:42
$t
$t
Definition: testCompression.php:74
PageArchive\__construct
__construct( $title, Config $config=null)
Definition: PageArchive.php:47
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:56
PageArchive\$title
Title $title
Definition: PageArchive.php:36
Title\getText
getText()
Get the text form (spaces not underscores) of the main part.
Definition: Title.php:1007
PageArchive\getPreviousRevision
getPreviousRevision( $timestamp)
Return the most-previous revision, either live or deleted, against the deleted revision given by time...
Definition: PageArchive.php:345