use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Revision\RevisionArchiveRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRecord;
/** @var RevisionStore */
private $revisionStore;
+ /** @var \MediaWiki\Revision\SlotRoleRegistry */
+ private $slotRoleRegistry;
+
private $guessedTitle = false, $props;
public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
parent::__construct( $mainModule, $moduleName, $modulePrefix );
$this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+ $this->slotRoleRegistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
}
public function execute() {
if ( !$fromRelRev ) {
$this->dieWithError( 'apierror-compare-relative-to-nothing' );
}
+ if ( $params['torelative'] !== 'cur' && $fromRelRev instanceof RevisionArchiveRecord ) {
+ // RevisionStore's getPreviousRevision/getNextRevision blow up
+ // when passed an RevisionArchiveRecord for a deleted page
+ $this->dieWithError( [ 'apierror-compare-relative-to-deleted', $params['torelative'] ] );
+ }
switch ( $params['torelative'] ) {
case 'prev':
// Swap 'from' and 'to'
- list( $toRev, $toRelRev2, $toValsRev ) = [ $fromRev, $fromRelRev, $fromValsRev ];
- $fromRev = $this->revisionStore->getPreviousRevision( $fromRelRev );
+ list( $toRev, $toRelRev, $toValsRev ) = [ $fromRev, $fromRelRev, $fromValsRev ];
+ $fromRev = $this->revisionStore->getPreviousRevision( $toRelRev );
$fromRelRev = $fromRev;
$fromValsRev = $fromRev;
+ if ( !$fromRev ) {
+ $title = Title::newFromLinkTarget( $toRelRev->getPageAsLinkTarget() );
+ $this->addWarning( [
+ 'apiwarn-compare-no-prev',
+ wfEscapeWikiText( $title->getPrefixedText() ),
+ $toRelRev->getId()
+ ] );
+
+ // (T203433) Create an empty dummy revision as the "previous".
+ // The main slot has to exist, the rest will be handled by DifferenceEngine.
+ $fromRev = $this->revisionStore->newMutableRevisionFromArray( [
+ 'title' => $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __METHOD__ )
+ ] );
+ $fromRev->setContent(
+ SlotRecord::MAIN,
+ $toRelRev->getContent( SlotRecord::MAIN, RevisionRecord::RAW )
+ ->getContentHandler()
+ ->makeEmptyContent()
+ );
+ }
break;
case 'next':
$toRev = $this->revisionStore->getNextRevision( $fromRelRev );
$toRelRev = $toRev;
$toValsRev = $toRev;
+ if ( !$toRev ) {
+ $title = Title::newFromLinkTarget( $fromRelRev->getPageAsLinkTarget() );
+ $this->addWarning( [
+ 'apiwarn-compare-no-next',
+ wfEscapeWikiText( $title->getPrefixedText() ),
+ $fromRelRev->getId()
+ ] );
+
+ // (T203433) The web UI treats "next" as "cur" in this case.
+ // Avoid repeating metadata by making a MutableRevisionRecord with no changes.
+ $toRev = MutableRevisionRecord::newFromParentRevision( $fromRelRev );
+ }
break;
case 'cur':
list( $toRev, $toRelRev, $toValsRev ) = $this->getDiffRevision( 'to', $params );
}
- // Handle missing from or to revisions
+ // Handle missing from or to revisions (should never happen)
+ // @codeCoverageIgnoreStart
if ( !$fromRev || !$toRev ) {
$this->dieWithError( 'apierror-baddiff' );
}
+ // @codeCoverageIgnoreEnd
// Handle revdel
if ( !$fromRev->audienceCan(
}
$guessedTitle = $this->guessTitle();
- if ( $guessedTitle && $role === SlotRecord::MAIN ) {
- // @todo: Use SlotRoleRegistry and do this for all slots
- return $guessedTitle->getContentModel();
+ if ( $guessedTitle ) {
+ return $this->slotRoleRegistry->getRoleHandler( $role )->getDefaultModel( $guessedTitle );
}
if ( isset( $params["fromcontentmodel-$role"] ) ) {
}
public function getAllowedParams() {
- $slotRoles = MediaWikiServices::getInstance()->getSlotRoleStore()->getMap();
- if ( !in_array( SlotRecord::MAIN, $slotRoles, true ) ) {
- $slotRoles[] = SlotRecord::MAIN;
- }
+ $slotRoles = $this->slotRoleRegistry->getKnownRoles();
sort( $slotRoles, SORT_STRING );
// Parameters for the 'from' and 'to' content