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