ImportableOldRevisionImporter.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. use Psr\Log\LoggerInterface;
  3. use Wikimedia\Rdbms\ILoadBalancer;
  4. /**
  5. * @since 1.31
  6. */
  7. class ImportableOldRevisionImporter implements OldRevisionImporter {
  8. /**
  9. * @var LoggerInterface
  10. */
  11. private $logger;
  12. /**
  13. * @var bool
  14. */
  15. private $doUpdates;
  16. /**
  17. * @var ILoadBalancer
  18. */
  19. private $loadBalancer;
  20. /**
  21. * @param bool $doUpdates
  22. * @param LoggerInterface $logger
  23. * @param ILoadBalancer $loadBalancer
  24. */
  25. public function __construct(
  26. $doUpdates,
  27. LoggerInterface $logger,
  28. ILoadBalancer $loadBalancer
  29. ) {
  30. $this->doUpdates = $doUpdates;
  31. $this->logger = $logger;
  32. $this->loadBalancer = $loadBalancer;
  33. }
  34. public function import( ImportableOldRevision $importableRevision, $doUpdates = true ) {
  35. $dbw = $this->loadBalancer->getConnectionRef( DB_MASTER );
  36. # Sneak a single revision into place
  37. $user = $importableRevision->getUserObj() ?: User::newFromName( $importableRevision->getUser() );
  38. if ( $user ) {
  39. $userId = intval( $user->getId() );
  40. $userText = $user->getName();
  41. } else {
  42. $userId = 0;
  43. $userText = $importableRevision->getUser();
  44. $user = new User;
  45. }
  46. // avoid memory leak...?
  47. Title::clearCaches();
  48. $page = WikiPage::factory( $importableRevision->getTitle() );
  49. $page->loadPageData( 'fromdbmaster' );
  50. if ( !$page->exists() ) {
  51. // must create the page...
  52. $pageId = $page->insertOn( $dbw );
  53. $created = true;
  54. $oldcountable = null;
  55. } else {
  56. $pageId = $page->getId();
  57. $created = false;
  58. // Note: sha1 has been in XML dumps since 2012. If you have an
  59. // older dump, the duplicate detection here won't work.
  60. if ( $importableRevision->getSha1Base36() !== false ) {
  61. $prior = $dbw->selectField( 'revision', '1',
  62. [ 'rev_page' => $pageId,
  63. 'rev_timestamp' => $dbw->timestamp( $importableRevision->getTimestamp() ),
  64. 'rev_sha1' => $importableRevision->getSha1Base36() ],
  65. __METHOD__
  66. );
  67. if ( $prior ) {
  68. // @todo FIXME: This could fail slightly for multiple matches :P
  69. $this->logger->debug( __METHOD__ . ": skipping existing revision for [[" .
  70. $importableRevision->getTitle()->getPrefixedText() . "]], timestamp " .
  71. $importableRevision->getTimestamp() . "\n" );
  72. return false;
  73. }
  74. }
  75. }
  76. if ( !$pageId ) {
  77. // This seems to happen if two clients simultaneously try to import the
  78. // same page
  79. $this->logger->debug( __METHOD__ . ': got invalid $pageId when importing revision of [[' .
  80. $importableRevision->getTitle()->getPrefixedText() . ']], timestamp ' .
  81. $importableRevision->getTimestamp() . "\n" );
  82. return false;
  83. }
  84. // Select previous version to make size diffs correct
  85. // @todo This assumes that multiple revisions of the same page are imported
  86. // in order from oldest to newest.
  87. $prevId = $dbw->selectField( 'revision', 'rev_id',
  88. [
  89. 'rev_page' => $pageId,
  90. 'rev_timestamp <= ' . $dbw->addQuotes( $dbw->timestamp( $importableRevision->getTimestamp() ) ),
  91. ],
  92. __METHOD__,
  93. [ 'ORDER BY' => [
  94. 'rev_timestamp DESC',
  95. 'rev_id DESC', // timestamp is not unique per page
  96. ]
  97. ]
  98. );
  99. # @todo FIXME: Use original rev_id optionally (better for backups)
  100. # Insert the row
  101. $revision = new Revision( [
  102. 'title' => $importableRevision->getTitle(),
  103. 'page' => $pageId,
  104. 'content_model' => $importableRevision->getModel(),
  105. 'content_format' => $importableRevision->getFormat(),
  106. // XXX: just set 'content' => $wikiRevision->getContent()?
  107. 'text' => $importableRevision->getContent()->serialize( $importableRevision->getFormat() ),
  108. 'comment' => $importableRevision->getComment(),
  109. 'user' => $userId,
  110. 'user_text' => $userText,
  111. 'timestamp' => $importableRevision->getTimestamp(),
  112. 'minor_edit' => $importableRevision->getMinor(),
  113. 'parent_id' => $prevId,
  114. ] );
  115. $revision->insertOn( $dbw );
  116. $changed = $page->updateIfNewerOn( $dbw, $revision );
  117. $tags = $importableRevision->getTags();
  118. if ( $tags !== [] ) {
  119. ChangeTags::addTags( $tags, null, $revision->getId() );
  120. }
  121. if ( $changed !== false && $this->doUpdates ) {
  122. $this->logger->debug( __METHOD__ . ": running updates\n" );
  123. // countable/oldcountable stuff is handled in WikiImporter::finishImportPage
  124. $page->doEditUpdates(
  125. $revision,
  126. $user,
  127. [ 'created' => $created, 'oldcountable' => 'no-change' ]
  128. );
  129. }
  130. return true;
  131. }
  132. }