MediaWiki REL1_35
ImportableOldRevisionImporter.php
Go to the documentation of this file.
1<?php
2
6use Psr\Log\LoggerInterface;
8
13
17 private $logger;
18
22 private $doUpdates;
23
28
33
38
46 public function __construct(
48 LoggerInterface $logger,
52 ) {
53 $this->doUpdates = $doUpdates;
54 $this->logger = $logger;
55 $this->loadBalancer = $loadBalancer;
56 $this->revisionStore = $revisionStore;
57 // @todo: temporary - remove when FileImporter extension is updated
58 if ( !$slotRoleRegistry ) {
59 $slotRoleRegistry = \MediaWiki\MediaWikiServices::getInstance()->getSlotRoleRegistry();
60 }
61 $this->slotRoleRegistry = $slotRoleRegistry;
62 }
63
64 public function import( ImportableOldRevision $importableRevision, $doUpdates = true ) {
65 $dbw = $this->loadBalancer->getConnectionRef( DB_MASTER );
66
67 # Sneak a single revision into place
68 $user = $importableRevision->getUserObj() ?: User::newFromName( $importableRevision->getUser() );
69 if ( $user ) {
70 $userId = intval( $user->getId() );
71 $userText = $user->getName();
72 } else {
73 $userId = 0;
74 $userText = $importableRevision->getUser();
75 $user = new User;
76 }
77
78 // avoid memory leak...?
79 Title::clearCaches();
80
81 $page = WikiPage::factory( $importableRevision->getTitle() );
82 $page->loadPageData( 'fromdbmaster' );
83 if ( !$page->exists() ) {
84 // must create the page...
85 $pageId = $page->insertOn( $dbw );
86 $created = true;
87 $oldcountable = null;
88 } else {
89 $pageId = $page->getId();
90 $created = false;
91
92 // Note: sha1 has been in XML dumps since 2012. If you have an
93 // older dump, the duplicate detection here won't work.
94 if ( $importableRevision->getSha1Base36() !== false ) {
95 $prior = $dbw->selectField( 'revision', '1',
96 [ 'rev_page' => $pageId,
97 'rev_timestamp' => $dbw->timestamp( $importableRevision->getTimestamp() ),
98 'rev_sha1' => $importableRevision->getSha1Base36() ],
99 __METHOD__
100 );
101 if ( $prior ) {
102 // @todo FIXME: This could fail slightly for multiple matches :P
103 $this->logger->debug( __METHOD__ . ": skipping existing revision for [[" .
104 $importableRevision->getTitle()->getPrefixedText() . "]], timestamp " .
105 $importableRevision->getTimestamp() . "\n" );
106 return false;
107 }
108 }
109 }
110
111 if ( !$pageId ) {
112 // This seems to happen if two clients simultaneously try to import the
113 // same page
114 $this->logger->debug( __METHOD__ . ': got invalid $pageId when importing revision of [[' .
115 $importableRevision->getTitle()->getPrefixedText() . ']], timestamp ' .
116 $importableRevision->getTimestamp() . "\n" );
117 return false;
118 }
119
120 // Select previous version to make size diffs correct
121 // @todo This assumes that multiple revisions of the same page are imported
122 // in order from oldest to newest.
123 $qi = $this->revisionStore->getQueryInfo();
124 $prevRevRow = $dbw->selectRow( $qi['tables'], $qi['fields'],
125 [
126 'rev_page' => $pageId,
127 'rev_timestamp <= ' . $dbw->addQuotes( $dbw->timestamp( $importableRevision->getTimestamp() ) ),
128 ],
129 __METHOD__,
130 [ 'ORDER BY' => [
131 'rev_timestamp DESC',
132 'rev_id DESC', // timestamp is not unique per page
133 ]
134 ],
135 $qi['joins']
136 );
137
138 # @todo FIXME: Use original rev_id optionally (better for backups)
139 # Insert the row
140 $revisionRecord = new MutableRevisionRecord( $importableRevision->getTitle() );
141 $revisionRecord->setParentId( $prevRevRow ? (int)$prevRevRow->rev_id : 0 );
142 $revisionRecord->setComment(
143 CommentStoreComment::newUnsavedComment( $importableRevision->getComment() )
144 );
145
146 try {
147 $revUser = User::newFromAnyId(
148 $userId,
149 $userText,
150 null
151 );
152 } catch ( InvalidArgumentException $ex ) {
153 $revUser = RequestContext::getMain()->getUser();
154 }
155 $revisionRecord->setUser( $revUser );
156
157 $originalRevision = $prevRevRow
158 ? $this->revisionStore->newRevisionFromRow(
159 $prevRevRow,
160 IDBAccessObject::READ_LATEST,
161 $importableRevision->getTitle()
162 )
163 : null;
164
165 foreach ( $importableRevision->getSlotRoles() as $role ) {
166 if ( !$this->slotRoleRegistry->isDefinedRole( $role ) ) {
167 throw new MWException( "Undefined slot role $role" );
168 }
169
170 $newContent = $importableRevision->getContent( $role );
171 if ( !$originalRevision || !$originalRevision->hasSlot( $role ) ) {
172 $revisionRecord->setContent( $role, $newContent );
173 } else {
174 $originalSlot = $originalRevision->getSlot( $role );
175 if ( !$originalSlot->hasSameContent( $importableRevision->getSlot( $role ) ) ) {
176 $revisionRecord->setContent( $role, $newContent );
177 } else {
178 $revisionRecord->inheritSlot( $originalRevision->getSlot( $role ) );
179 }
180 }
181 }
182
183 $revisionRecord->setTimestamp( $importableRevision->getTimestamp() );
184 $revisionRecord->setMinorEdit( $importableRevision->getMinor() );
185 $revisionRecord->setPageId( $pageId );
186
187 $latestRevId = $page->getLatest();
188
189 $inserted = $this->revisionStore->insertRevisionOn( $revisionRecord, $dbw );
190 if ( $latestRevId ) {
191 // If not found (false), cast to 0 so that the page is updated
192 // Just to be on the safe side, even though it should always be found
193 $latestRevTimestamp = (int)$this->revisionStore->getTimestampFromId(
194 $latestRevId,
195 RevisionStore::READ_LATEST
196 );
197 } else {
198 $latestRevTimestamp = 0;
199 }
200 if ( $importableRevision->getTimestamp() > $latestRevTimestamp ) {
201 $changed = $page->updateRevisionOn( $dbw, $inserted, $latestRevId );
202 } else {
203 $changed = false;
204 }
205
206 $tags = $importableRevision->getTags();
207 if ( $tags !== [] ) {
208 ChangeTags::addTags( $tags, null, $inserted->getId() );
209 }
210
211 if ( $changed !== false && $this->doUpdates ) {
212 $this->logger->debug( __METHOD__ . ": running updates" );
213 // countable/oldcountable stuff is handled in WikiImporter::finishImportPage
214 // @todo replace deprecated function
215 $page->doEditUpdates(
216 $inserted,
217 $user,
218 [ 'created' => $created, 'oldcountable' => 'no-change' ]
219 );
220 }
221
222 return true;
223 }
224
225}
static addTags( $tags, $rc_id=null, $rev_id=null, $log_id=null, $params=null, RecentChange $rc=null)
Add tags to a change given its rc_id, rev_id and/or log_id.
__construct( $doUpdates, LoggerInterface $logger, ILoadBalancer $loadBalancer, RevisionStore $revisionStore, SlotRoleRegistry $slotRoleRegistry=null)
MediaWiki exception.
Service for looking up page revisions.
A registry service for SlotRoleHandlers, used to define which slot roles are available on which page.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:60
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:541
static newFromAnyId( $userId, $userName, $actorId, $dbDomain=false)
Static factory method for creation from an ID, name, and/or actor ID.
Definition User.php:616
getContent( $role=SlotRecord::MAIN)
Database cluster connection, tracking, load balancing, and transaction manager interface.
const DB_MASTER
Definition defines.php:29
return true
Definition router.php:92