Merge "Make extension data JSON-serializable #1 - forward-compat."

This commit is contained in:
jenkins-bot 2020-10-30 17:56:20 +00:00 committed by Gerrit Code Review
commit 5edb1fd72a
2 changed files with 140 additions and 2 deletions

View file

@ -68,7 +68,7 @@ class TemplateDataHooks {
$format = $content->getContentHandler()->getDefaultFormat();
$editInfo = $page->prepareContentForEdit( $content, null, $user, $format );
$templateDataStatus = $editInfo->output->getExtensionData( 'TemplateDataStatus' );
$templateDataStatus = self::getStatusFromParserOutput( $editInfo->output );
if ( $templateDataStatus instanceof Status && !$templateDataStatus->isOK() ) {
// Abort edit, show error message from TemplateDataBlob::getStatus
$status->merge( $templateDataStatus );
@ -110,7 +110,7 @@ class TemplateDataHooks {
$status = $ti->getStatus();
if ( !$status->isOK() ) {
$parser->getOutput()->setExtensionData( 'TemplateDataStatus', $status );
self::setStatusToParserOutput( $parser->getOutput(), $status );
return '<div class="errorbox">' . $status->getHTML() . '</div>';
}
@ -212,4 +212,69 @@ class TemplateDataHooks {
$tplData[$tplTitle] = $tdb->getData();
}
}
/**
* Write the status to ParserOutput object.
* @param ParserOutput $parserOutput
* @param Status $status
*/
public static function setStatusToParserOutput( ParserOutput $parserOutput, Status $status ) {
$parserOutput->setExtensionData( 'TemplateDataStatus', $status );
// TODO: make JSON serializable. See T266252.
// $parserOutput->setExtensionData( 'TemplateDataStatus',
// self::jsonSerializeStatus( $status ) );
}
/**
* @param ParserOutput $parserOutput
* @return Status|null
*/
public static function getStatusFromParserOutput( ParserOutput $parserOutput ) {
$status = $parserOutput->getExtensionData( 'TemplateDataStatus' );
if ( is_array( $status ) ) {
return self::newStatusFromJson( $status );
}
return $status;
}
/**
* @param array $status contains StatusValue ok and errors fields (does not serialize value)
* @return Status
*/
public static function newStatusFromJson( array $status ) : Status {
if ( $status['ok'] ) {
return Status::newGood();
} else {
$statusObj = new Status();
$errors = $status['errors'];
foreach ( $errors as $error ) {
$statusObj->fatal( $error['message'], ...$error['params'] );
}
$warnings = $status['warnings'];
foreach ( $warnings as $warning ) {
$statusObj->warning( $warning['message'], ...$warning['params'] );
}
return $statusObj;
}
}
/**
* @param Status $status
* @return array contains StatusValue ok and errors fields (does not serialize value)
*/
public static function jsonSerializeStatus( Status $status ) : array {
if ( $status->isOK() ) {
return [
'ok' => true
];
} else {
list( $errorsOnlyStatus, $warningsOnlyStatus ) = $status->splitByErrorType();
// note that non-scalar values are not supported in errors or warnings
return [
'ok' => false,
'errors' => $errorsOnlyStatus->getErrors(),
'warnings' => $warningsOnlyStatus->getErrors()
];
}
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* @group TemplateData
* @covers \TemplateDataHooks::setStatusToParserOutput
* @covers \TemplateDataHooks::getStatusFromParserOutput
*/
class SerializationTest extends MediaWikiTestCase {
public function testParserOutputPersistenceForwardCompatibility() {
$output = new ParserOutput();
$status = Status::newFatal( 'a', 'b', 'c' );
$status->fatal( 'f' );
$status->warning( 'd', 'e' );
// Set JSONified state. Should work before we set JSON-serializable data,
// to be robust against old code reading new data after a rollback.
$output->setExtensionData( 'TemplateDataStatus',
TemplateDataHooks::jsonSerializeStatus( $status ) );
$result = TemplateDataHooks::getStatusFromParserOutput( $output );
$this->assertEquals( $status->getStatusValue(), $result->getStatusValue() );
$this->assertEquals( $status->__toString(), $result->__toString() );
}
public function testParserOutputPersistenceBackwardCompatibility() {
$output = new ParserOutput();
$status = Status::newFatal( 'a', 'b', 'c' );
$status->fatal( 'f' );
$status->warning( 'd', 'e' );
// Set the object directly. Should still work once we normally set JSON-serializable data.
$output->setExtensionData( 'TemplateDataStatus', $status );
$result = TemplateDataHooks::getStatusFromParserOutput( $output );
$this->assertEquals( $status->getStatusValue(), $result->getStatusValue() );
$this->assertEquals( $status->__toString(), $result->__toString() );
}
public function provideStatus() {
yield [ Status::newGood() ];
$status = Status::newFatal( 'a', 'b', 'c' );
$status->fatal( 'f' );
$status->warning( 'd', 'e' );
yield [ $status ];
}
/**
* @dataProvider provideStatus
* @covers \TemplateDataHooks::setStatusToParserOutput
* @covers \TemplateDataHooks::getStatusFromParserOutput
*/
public function testParserOutputPersistenceRoundTrip( Status $status ) {
$parserOutput = new ParserOutput();
TemplateDataHooks::setStatusToParserOutput( $parserOutput, $status );
$result = TemplateDataHooks::getStatusFromParserOutput( $parserOutput );
$this->assertEquals( $status->getStatusValue(), $result->getStatusValue() );
$this->assertEquals( $status->__toString(), $result->__toString() );
}
/**
* @dataProvider provideStatus
* @covers \TemplateDataHooks::jsonSerializeStatus
* @covers \TemplateDataHooks::newStatusFromJson
*/
public function testJsonRoundTrip( Status $status ) {
$json = TemplateDataHooks::jsonSerializeStatus( $status );
$result = TemplateDataHooks::newStatusFromJson( $json );
$this->assertEquals( $status->getStatusValue(), $result->getStatusValue() );
$this->assertEquals( $status->__toString(), $result->__toString() );
}
}