MovePage::move()   D
last analyzed

Complexity

Conditions 14
Paths 217

Size

Total Lines 184
Code Lines 123

Duplication

Lines 7
Ratio 3.8 %

Importance

Changes 0
Metric Value
cc 14
eloc 123
c 0
b 0
f 0
nc 217
nop 3
dl 7
loc 184
rs 4.3305

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License along
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
 * http://www.gnu.org/copyleft/gpl.html
18
 *
19
 * @file
20
 */
21
22
use MediaWiki\MediaWikiServices;
23
24
/**
25
 * Handles the backend logic of moving a page from one title
26
 * to another.
27
 *
28
 * @since 1.24
29
 */
30
class MovePage {
31
32
	/**
33
	 * @var Title
34
	 */
35
	protected $oldTitle;
36
37
	/**
38
	 * @var Title
39
	 */
40
	protected $newTitle;
41
42
	public function __construct( Title $oldTitle, Title $newTitle ) {
43
		$this->oldTitle = $oldTitle;
44
		$this->newTitle = $newTitle;
45
	}
46
47
	public function checkPermissions( User $user, $reason ) {
48
		$status = new Status();
49
50
		$errors = wfMergeErrorArrays(
51
			$this->oldTitle->getUserPermissionsErrors( 'move', $user ),
52
			$this->oldTitle->getUserPermissionsErrors( 'edit', $user ),
53
			$this->newTitle->getUserPermissionsErrors( 'move-target', $user ),
54
			$this->newTitle->getUserPermissionsErrors( 'edit', $user )
55
		);
56
57
		// Convert into a Status object
58
		if ( $errors ) {
59
			foreach ( $errors as $error ) {
60
				call_user_func_array( [ $status, 'fatal' ], $error );
61
			}
62
		}
63
64
		if ( EditPage::matchSummarySpamRegex( $reason ) !== false ) {
65
			// This is kind of lame, won't display nice
66
			$status->fatal( 'spamprotectiontext' );
67
		}
68
69
		$tp = $this->newTitle->getTitleProtection();
70
		if ( $tp !== false && !$user->isAllowed( $tp['permission'] ) ) {
71
				$status->fatal( 'cantmove-titleprotected' );
72
		}
73
74
		Hooks::run( 'MovePageCheckPermissions',
75
			[ $this->oldTitle, $this->newTitle, $user, $reason, $status ]
76
		);
77
78
		return $status;
79
	}
80
81
	/**
82
	 * Does various sanity checks that the move is
83
	 * valid. Only things based on the two titles
84
	 * should be checked here.
85
	 *
86
	 * @return Status
87
	 */
88
	public function isValidMove() {
89
		global $wgContentHandlerUseDB;
90
		$status = new Status();
91
92
		if ( $this->oldTitle->equals( $this->newTitle ) ) {
93
			$status->fatal( 'selfmove' );
94
		}
95
		if ( !$this->oldTitle->isMovable() ) {
96
			$status->fatal( 'immobile-source-namespace', $this->oldTitle->getNsText() );
97
		}
98
		if ( $this->newTitle->isExternal() ) {
99
			$status->fatal( 'immobile-target-namespace-iw' );
100
		}
101
		if ( !$this->newTitle->isMovable() ) {
102
			$status->fatal( 'immobile-target-namespace', $this->newTitle->getNsText() );
103
		}
104
105
		$oldid = $this->oldTitle->getArticleID();
106
107
		if ( strlen( $this->newTitle->getDBkey() ) < 1 ) {
108
			$status->fatal( 'articleexists' );
109
		}
110
		if (
111
			( $this->oldTitle->getDBkey() == '' ) ||
112
			( !$oldid ) ||
113
			( $this->newTitle->getDBkey() == '' )
114
		) {
115
			$status->fatal( 'badarticleerror' );
116
		}
117
118
		# The move is allowed only if (1) the target doesn't exist, or
119
		# (2) the target is a redirect to the source, and has no history
120
		# (so we can undo bad moves right after they're done).
121
		if ( $this->newTitle->getArticleID() && !$this->isValidMoveTarget() ) {
122
			$status->fatal( 'articleexists' );
123
		}
124
125
		// Content model checks
126
		if ( !$wgContentHandlerUseDB &&
127
			$this->oldTitle->getContentModel() !== $this->newTitle->getContentModel() ) {
128
			// can't move a page if that would change the page's content model
129
			$status->fatal(
130
				'bad-target-model',
131
				ContentHandler::getLocalizedName( $this->oldTitle->getContentModel() ),
132
				ContentHandler::getLocalizedName( $this->newTitle->getContentModel() )
133
			);
134
		} elseif (
135
			!ContentHandler::getForTitle( $this->oldTitle )->canBeUsedOn( $this->newTitle )
136
		) {
137
			$status->fatal(
138
				'content-not-allowed-here',
139
				ContentHandler::getLocalizedName( $this->oldTitle->getContentModel() ),
140
				$this->newTitle->getPrefixedText()
141
			);
142
		}
143
144
		// Image-specific checks
145
		if ( $this->oldTitle->inNamespace( NS_FILE ) ) {
146
			$status->merge( $this->isValidFileMove() );
147
		}
148
149
		if ( $this->newTitle->inNamespace( NS_FILE ) && !$this->oldTitle->inNamespace( NS_FILE ) ) {
150
			$status->fatal( 'nonfile-cannot-move-to-file' );
151
		}
152
153
		// Hook for extensions to say a title can't be moved for technical reasons
154
		Hooks::run( 'MovePageIsValidMove', [ $this->oldTitle, $this->newTitle, $status ] );
155
156
		return $status;
157
	}
158
159
	/**
160
	 * Sanity checks for when a file is being moved
161
	 *
162
	 * @return Status
163
	 */
164
	protected function isValidFileMove() {
165
		$status = new Status();
166
		$file = wfLocalFile( $this->oldTitle );
167
		$file->load( File::READ_LATEST );
168
		if ( $file->exists() ) {
169
			if ( $this->newTitle->getText() != wfStripIllegalFilenameChars( $this->newTitle->getText() ) ) {
170
				$status->fatal( 'imageinvalidfilename' );
171
			}
172
			if ( !File::checkExtensionCompatibility( $file, $this->newTitle->getDBkey() ) ) {
0 ignored issues
show
Bug introduced by
It seems like $file defined by wfLocalFile($this->oldTitle) on line 166 can be null; however, File::checkExtensionCompatibility() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Bug Best Practice introduced by
The expression \File::checkExtensionCom...->newTitle->getDBkey()) of type null|boolean is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
173
				$status->fatal( 'imagetypemismatch' );
174
			}
175
		}
176
177
		if ( !$this->newTitle->inNamespace( NS_FILE ) ) {
178
			$status->fatal( 'imagenocrossnamespace' );
179
		}
180
181
		return $status;
182
	}
183
184
	/**
185
	 * Checks if $this can be moved to a given Title
186
	 * - Selects for update, so don't call it unless you mean business
187
	 *
188
	 * @since 1.25
189
	 * @return bool
190
	 */
191
	protected function isValidMoveTarget() {
192
		# Is it an existing file?
193
		if ( $this->newTitle->inNamespace( NS_FILE ) ) {
194
			$file = wfLocalFile( $this->newTitle );
195
			$file->load( File::READ_LATEST );
196
			if ( $file->exists() ) {
197
				wfDebug( __METHOD__ . ": file exists\n" );
198
				return false;
199
			}
200
		}
201
		# Is it a redirect with no history?
202
		if ( !$this->newTitle->isSingleRevRedirect() ) {
203
			wfDebug( __METHOD__ . ": not a one-rev redirect\n" );
204
			return false;
205
		}
206
		# Get the article text
207
		$rev = Revision::newFromTitle( $this->newTitle, false, Revision::READ_LATEST );
208
		if ( !is_object( $rev ) ) {
209
			return false;
210
		}
211
		$content = $rev->getContent();
212
		# Does the redirect point to the source?
213
		# Or is it a broken self-redirect, usually caused by namespace collisions?
214
		$redirTitle = $content ? $content->getRedirectTarget() : null;
215
216
		if ( $redirTitle ) {
217
			if ( $redirTitle->getPrefixedDBkey() !== $this->oldTitle->getPrefixedDBkey() &&
218
				$redirTitle->getPrefixedDBkey() !== $this->newTitle->getPrefixedDBkey() ) {
219
				wfDebug( __METHOD__ . ": redirect points to other page\n" );
220
				return false;
221
			} else {
222
				return true;
223
			}
224
		} else {
225
			# Fail safe (not a redirect after all. strange.)
226
			wfDebug( __METHOD__ . ": failsafe: database says " . $this->newTitle->getPrefixedDBkey() .
227
				" is a redirect, but it doesn't contain a valid redirect.\n" );
228
			return false;
229
		}
230
	}
231
232
	/**
233
	 * @param User $user
234
	 * @param string $reason
235
	 * @param bool $createRedirect
236
	 * @return Status
237
	 */
238
	public function move( User $user, $reason, $createRedirect ) {
239
		global $wgCategoryCollation;
240
241
		Hooks::run( 'TitleMove', [ $this->oldTitle, $this->newTitle, $user ] );
242
243
		// If it is a file, move it first.
244
		// It is done before all other moving stuff is done because it's hard to revert.
245
		$dbw = wfGetDB( DB_MASTER );
246
		if ( $this->oldTitle->getNamespace() == NS_FILE ) {
247
			$file = wfLocalFile( $this->oldTitle );
248
			$file->load( File::READ_LATEST );
249
			if ( $file->exists() ) {
250
				$status = $file->move( $this->newTitle );
251
				if ( !$status->isOK() ) {
252
					return $status;
253
				}
254
			}
255
			// Clear RepoGroup process cache
256
			RepoGroup::singleton()->clearCache( $this->oldTitle );
257
			RepoGroup::singleton()->clearCache( $this->newTitle ); # clear false negative cache
258
		}
259
260
		$dbw->startAtomic( __METHOD__ );
261
262
		Hooks::run( 'TitleMoveStarting', [ $this->oldTitle, $this->newTitle, $user ] );
263
264
		$pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE );
265
		$protected = $this->oldTitle->isProtected();
266
267
		// Do the actual move; if this fails, it will throw an MWException(!)
268
		$nullRevision = $this->moveToInternal( $user, $this->newTitle, $reason, $createRedirect );
269
270
		// Refresh the sortkey for this row.  Be careful to avoid resetting
271
		// cl_timestamp, which may disturb time-based lists on some sites.
272
		// @todo This block should be killed, it's duplicating code
273
		// from LinksUpdate::getCategoryInsertions() and friends.
274
		$prefixes = $dbw->select(
275
			'categorylinks',
276
			[ 'cl_sortkey_prefix', 'cl_to' ],
277
			[ 'cl_from' => $pageid ],
278
			__METHOD__
279
		);
280 View Code Duplication
		if ( $this->newTitle->getNamespace() == NS_CATEGORY ) {
281
			$type = 'subcat';
282
		} elseif ( $this->newTitle->getNamespace() == NS_FILE ) {
283
			$type = 'file';
284
		} else {
285
			$type = 'page';
286
		}
287
		foreach ( $prefixes as $prefixRow ) {
288
			$prefix = $prefixRow->cl_sortkey_prefix;
289
			$catTo = $prefixRow->cl_to;
290
			$dbw->update( 'categorylinks',
291
				[
292
					'cl_sortkey' => Collation::singleton()->getSortKey(
293
							$this->newTitle->getCategorySortkey( $prefix ) ),
294
					'cl_collation' => $wgCategoryCollation,
295
					'cl_type' => $type,
296
					'cl_timestamp=cl_timestamp' ],
297
				[
298
					'cl_from' => $pageid,
299
					'cl_to' => $catTo ],
300
				__METHOD__
301
			);
302
		}
303
304
		$redirid = $this->oldTitle->getArticleID();
305
306
		if ( $protected ) {
307
			# Protect the redirect title as the title used to be...
308
			$res = $dbw->select(
309
				'page_restrictions',
310
				'*',
311
				[ 'pr_page' => $pageid ],
312
				__METHOD__,
313
				'FOR UPDATE'
314
			);
315
			$rowsInsert = [];
316
			foreach ( $res as $row ) {
317
				$rowsInsert[] = [
318
					'pr_page' => $redirid,
319
					'pr_type' => $row->pr_type,
320
					'pr_level' => $row->pr_level,
321
					'pr_cascade' => $row->pr_cascade,
322
					'pr_user' => $row->pr_user,
323
					'pr_expiry' => $row->pr_expiry
324
				];
325
			}
326
			$dbw->insert( 'page_restrictions', $rowsInsert, __METHOD__, [ 'IGNORE' ] );
327
328
			// Build comment for log
329
			$comment = wfMessage(
330
				'prot_1movedto2',
331
				$this->oldTitle->getPrefixedText(),
332
				$this->newTitle->getPrefixedText()
333
			)->inContentLanguage()->text();
334
			if ( $reason ) {
335
				$comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
336
			}
337
338
			// reread inserted pr_ids for log relation
339
			$insertedPrIds = $dbw->select(
340
				'page_restrictions',
341
				'pr_id',
342
				[ 'pr_page' => $redirid ],
343
				__METHOD__
344
			);
345
			$logRelationsValues = [];
346
			foreach ( $insertedPrIds as $prid ) {
347
				$logRelationsValues[] = $prid->pr_id;
348
			}
349
350
			// Update the protection log
351
			$logEntry = new ManualLogEntry( 'protect', 'move_prot' );
352
			$logEntry->setTarget( $this->newTitle );
353
			$logEntry->setComment( $comment );
354
			$logEntry->setPerformer( $user );
355
			$logEntry->setParameters( [
356
				'4::oldtitle' => $this->oldTitle->getPrefixedText(),
357
			] );
358
			$logEntry->setRelations( [ 'pr_id' => $logRelationsValues ] );
359
			$logId = $logEntry->insert();
360
			$logEntry->publish( $logId );
361
		}
362
363
		// Update *_from_namespace fields as needed
364
		if ( $this->oldTitle->getNamespace() != $this->newTitle->getNamespace() ) {
365
			$dbw->update( 'pagelinks',
366
				[ 'pl_from_namespace' => $this->newTitle->getNamespace() ],
367
				[ 'pl_from' => $pageid ],
368
				__METHOD__
369
			);
370
			$dbw->update( 'templatelinks',
371
				[ 'tl_from_namespace' => $this->newTitle->getNamespace() ],
372
				[ 'tl_from' => $pageid ],
373
				__METHOD__
374
			);
375
			$dbw->update( 'imagelinks',
376
				[ 'il_from_namespace' => $this->newTitle->getNamespace() ],
377
				[ 'il_from' => $pageid ],
378
				__METHOD__
379
			);
380
		}
381
382
		# Update watchlists
383
		$oldtitle = $this->oldTitle->getDBkey();
384
		$newtitle = $this->newTitle->getDBkey();
385
		$oldsnamespace = MWNamespace::getSubject( $this->oldTitle->getNamespace() );
386
		$newsnamespace = MWNamespace::getSubject( $this->newTitle->getNamespace() );
387
		if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) {
388
			$store = MediaWikiServices::getInstance()->getWatchedItemStore();
389
			$store->duplicateAllAssociatedEntries( $this->oldTitle, $this->newTitle );
390
		}
391
392
		Hooks::run(
393
			'TitleMoveCompleting',
394
			[ $this->oldTitle, $this->newTitle,
395
				$user, $pageid, $redirid, $reason, $nullRevision ]
396
		);
397
398
		$dbw->endAtomic( __METHOD__ );
399
400
		$params = [
401
			&$this->oldTitle,
402
			&$this->newTitle,
403
			&$user,
404
			$pageid,
405
			$redirid,
406
			$reason,
407
			$nullRevision
408
		];
409
		// Keep each single hook handler atomic
410
		DeferredUpdates::addUpdate(
411
			new AtomicSectionUpdate(
412
				$dbw,
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 245 can be null; however, AtomicSectionUpdate::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
413
				__METHOD__,
414
				function () use ( $params ) {
415
					Hooks::run( 'TitleMoveComplete', $params );
416
				}
417
			)
418
		);
419
420
		return Status::newGood();
421
	}
422
423
	/**
424
	 * Move page to a title which is either a redirect to the
425
	 * source page or nonexistent
426
	 *
427
	 * @fixme This was basically directly moved from Title, it should be split into smaller functions
428
	 * @param User $user the User doing the move
429
	 * @param Title $nt The page to move to, which should be a redirect or non-existent
430
	 * @param string $reason The reason for the move
431
	 * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check
432
	 *   if the user has the suppressredirect right
433
	 * @return Revision the revision created by the move
434
	 * @throws MWException
435
	 */
436
	private function moveToInternal( User $user, &$nt, $reason = '', $createRedirect = true ) {
437
		global $wgContLang;
438
439
		if ( $nt->exists() ) {
440
			$moveOverRedirect = true;
441
			$logType = 'move_redir';
442
		} else {
443
			$moveOverRedirect = false;
444
			$logType = 'move';
445
		}
446
447
		if ( $moveOverRedirect ) {
448
			$overwriteMessage = wfMessage(
449
					'delete_and_move_reason',
450
					$this->oldTitle->getPrefixedText()
451
				)->text();
452
			$newpage = WikiPage::factory( $nt );
453
			$errs = [];
454
			$status = $newpage->doDeleteArticleReal(
455
				$overwriteMessage,
456
				/* $suppress */ false,
457
				$nt->getArticleID(),
458
				/* $commit */ false,
459
				$errs,
460
				$user
461
			);
462
463
			if ( !$status->isGood() ) {
464
				throw new MWException( 'Failed to delete page-move revision: ' . $status );
465
			}
466
467
			$nt->resetArticleID( false );
468
		}
469
470
		if ( $createRedirect ) {
471
			if ( $this->oldTitle->getNamespace() == NS_CATEGORY
472
				&& !wfMessage( 'category-move-redirect-override' )->inContentLanguage()->isDisabled()
473
			) {
474
				$redirectContent = new WikitextContent(
475
					wfMessage( 'category-move-redirect-override' )
476
						->params( $nt->getPrefixedText() )->inContentLanguage()->plain() );
477
			} else {
478
				$contentHandler = ContentHandler::getForTitle( $this->oldTitle );
479
				$redirectContent = $contentHandler->makeRedirectContent( $nt,
480
					wfMessage( 'move-redirect-text' )->inContentLanguage()->plain() );
481
			}
482
483
			// NOTE: If this page's content model does not support redirects, $redirectContent will be null.
484
		} else {
485
			$redirectContent = null;
486
		}
487
488
		// Figure out whether the content model is no longer the default
489
		$oldDefault = ContentHandler::getDefaultModelFor( $this->oldTitle );
490
		$contentModel = $this->oldTitle->getContentModel();
491
		$newDefault = ContentHandler::getDefaultModelFor( $nt );
492
		$defaultContentModelChanging = ( $oldDefault !== $newDefault
493
			&& $oldDefault === $contentModel );
494
495
		// bug 57084: log_page should be the ID of the *moved* page
496
		$oldid = $this->oldTitle->getArticleID();
497
		$logTitle = clone $this->oldTitle;
498
499
		$logEntry = new ManualLogEntry( 'move', $logType );
500
		$logEntry->setPerformer( $user );
501
		$logEntry->setTarget( $logTitle );
502
		$logEntry->setComment( $reason );
503
		$logEntry->setParameters( [
504
			'4::target' => $nt->getPrefixedText(),
505
			'5::noredir' => $redirectContent ? '0': '1',
506
		] );
507
508
		$formatter = LogFormatter::newFromEntry( $logEntry );
509
		$formatter->setContext( RequestContext::newExtraneousContext( $this->oldTitle ) );
510
		$comment = $formatter->getPlainActionText();
511
		if ( $reason ) {
512
			$comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
513
		}
514
		# Truncate for whole multibyte characters.
515
		$comment = $wgContLang->truncate( $comment, 255 );
516
517
		$dbw = wfGetDB( DB_MASTER );
518
519
		$oldpage = WikiPage::factory( $this->oldTitle );
520
		$oldcountable = $oldpage->isCountable();
521
522
		$newpage = WikiPage::factory( $nt );
523
524
		# Save a null revision in the page's history notifying of the move
525
		$nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true, $user );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, Revision::newNullRevision() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
526
		if ( !is_object( $nullRevision ) ) {
527
			throw new MWException( 'No valid null revision produced in ' . __METHOD__ );
528
		}
529
530
		$nullRevision->insertOn( $dbw );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, Revision::insertOn() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
531
532
		# Change the name of the target page:
533
		$dbw->update( 'page',
534
			/* SET */ [
535
				'page_namespace' => $nt->getNamespace(),
536
				'page_title' => $nt->getDBkey(),
537
			],
538
			/* WHERE */ [ 'page_id' => $oldid ],
539
			__METHOD__
540
		);
541
542
		if ( !$redirectContent ) {
543
			// Clean up the old title *before* reset article id - bug 45348
544
			WikiPage::onArticleDelete( $this->oldTitle );
545
		}
546
547
		$this->oldTitle->resetArticleID( 0 ); // 0 == non existing
548
		$nt->resetArticleID( $oldid );
549
		$newpage->loadPageData( WikiPage::READ_LOCKING ); // bug 46397
550
551
		$newpage->updateRevisionOn( $dbw, $nullRevision );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, WikiPage::updateRevisionOn() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
552
553
		Hooks::run( 'NewRevisionFromEditComplete',
554
			[ $newpage, $nullRevision, $nullRevision->getParentId(), $user ] );
555
556
		$newpage->doEditUpdates( $nullRevision, $user,
557
			[ 'changed' => false, 'moved' => true, 'oldcountable' => $oldcountable ] );
558
559
		// If the default content model changes, we need to populate rev_content_model
560
		if ( $defaultContentModelChanging ) {
561
			$dbw->update(
562
				'revision',
563
				[ 'rev_content_model' => $contentModel ],
564
				[ 'rev_page' => $nt->getArticleID(), 'rev_content_model IS NULL' ],
565
				__METHOD__
566
			);
567
		}
568
569
		WikiPage::onArticleCreate( $nt );
570
571
		# Recreate the redirect, this time in the other direction.
572
		if ( $redirectContent ) {
573
			$redirectArticle = WikiPage::factory( $this->oldTitle );
574
			$redirectArticle->loadFromRow( false, WikiPage::READ_LOCKING ); // bug 46397
575
			$newid = $redirectArticle->insertOn( $dbw );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, WikiPage::insertOn() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
576
			if ( $newid ) { // sanity
577
				$this->oldTitle->resetArticleID( $newid );
578
				$redirectRevision = new Revision( [
579
					'title' => $this->oldTitle, // for determining the default content model
580
					'page' => $newid,
581
					'user_text' => $user->getName(),
582
					'user' => $user->getId(),
583
					'comment' => $comment,
584
					'content' => $redirectContent ] );
585
				$redirectRevision->insertOn( $dbw );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, Revision::insertOn() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
586
				$redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
0 ignored issues
show
Bug introduced by
It seems like $dbw defined by wfGetDB(DB_MASTER) on line 517 can be null; however, WikiPage::updateRevisionOn() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
587
588
				Hooks::run( 'NewRevisionFromEditComplete',
589
					[ $redirectArticle, $redirectRevision, false, $user ] );
590
591
				$redirectArticle->doEditUpdates( $redirectRevision, $user, [ 'created' => true ] );
592
			}
593
		}
594
595
		# Log the move
596
		$logid = $logEntry->insert();
597
		$logEntry->publish( $logid );
598
599
		return $nullRevision;
600
	}
601
}
602