Yurik has uploaded a new change for review.
https://gerrit.wikimedia.org/r/160575
Change subject: abstract CodeContent, reworked JsonContent
......................................................................
abstract CodeContent, reworked JsonContent
* Merged common code from Css, JavaScript, Json Content objects into
an abstract CodeContent class
* Reworked JsonContent object:
** Support JSON decoding options
** Decoding produces a status object that may contain decoded object
** Saves optimally formatted, no spaces blob
** Removed beautifyJSON() - don't think we need it - encoding is different
for different use-cases, plus the errors should be handled properly.
** Table rendering is done the same as other code content - with a <pre>
Change-Id: Idbca6c091d61bf33174110dd3637a9a913e3503b
---
M includes/AutoLoader.php
M includes/content/CssContent.php
M includes/content/JavaScriptContent.php
M includes/content/JsonContent.php
M tests/phpunit/includes/content/JsonContentTest.php
5 files changed, 84 insertions(+), 150 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/75/160575/1
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 7c5de2a..14ffd89 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -375,6 +375,7 @@
# includes/content
'AbstractContent' => 'includes/content/AbstractContent.php',
+ 'CodeContent' => 'includes/content/CodeContent.php',
'CodeContentHandler' => 'includes/content/CodeContentHandler.php',
'Content' => 'includes/content/Content.php',
'ContentHandler' => 'includes/content/ContentHandler.php',
diff --git a/includes/content/CssContent.php b/includes/content/CssContent.php
index 8290603..753986e 100644
--- a/includes/content/CssContent.php
+++ b/includes/content/CssContent.php
@@ -30,7 +30,7 @@
*
* @ingroup Content
*/
-class CssContent extends TextContent {
+class CssContent extends CodeContent {
/**
* @param string $text CSS code.
@@ -41,37 +41,10 @@
}
/**
- * Returns a Content object with pre-save transformations applied using
- * Parser::preSaveTransform().
- *
- * @param Title $title
- * @param User $user
- * @param ParserOptions $popts
- *
- * @return CssContent
- *
- * @see TextContent::preSaveTransform
- */
- public function preSaveTransform( Title $title, User $user,
ParserOptions $popts ) {
- global $wgParser;
- // @todo Make pre-save transformation optional for script pages
-
- $text = $this->getNativeData();
- $pst = $wgParser->preSaveTransform( $text, $title, $user,
$popts );
-
- return new static( $pst );
- }
-
- /**
* @return string CSS wrapped in a <pre> tag.
*/
protected function getHtml() {
- $html = "";
- $html .= "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n";
- $html .= htmlspecialchars( $this->getNativeData() );
- $html .= "\n</pre>\n";
-
- return $html;
+ return $this->codeToPreElement( 'mw-css' );
}
}
diff --git a/includes/content/JavaScriptContent.php
b/includes/content/JavaScriptContent.php
index c0194c2..f044d11 100644
--- a/includes/content/JavaScriptContent.php
+++ b/includes/content/JavaScriptContent.php
@@ -30,7 +30,7 @@
*
* @ingroup Content
*/
-class JavaScriptContent extends TextContent {
+class JavaScriptContent extends CodeContent {
/**
* @param string $text JavaScript code.
@@ -41,36 +41,10 @@
}
/**
- * Returns a Content object with pre-save transformations applied using
- * Parser::preSaveTransform().
- *
- * @param Title $title
- * @param User $user
- * @param ParserOptions $popts
- *
- * @return JavaScriptContent
- */
- public function preSaveTransform( Title $title, User $user,
ParserOptions $popts ) {
- global $wgParser;
- // @todo Make pre-save transformation optional for script pages
- // See bug #32858
-
- $text = $this->getNativeData();
- $pst = $wgParser->preSaveTransform( $text, $title, $user,
$popts );
-
- return new static( $pst );
- }
-
- /**
* @return string JavaScript wrapped in a <pre> tag.
*/
protected function getHtml() {
- $html = "";
- $html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n";
- $html .= htmlspecialchars( $this->getNativeData() );
- $html .= "\n</pre>\n";
-
- return $html;
+ return $this->codeToPreElement( 'mw-js' );
}
}
diff --git a/includes/content/JsonContent.php b/includes/content/JsonContent.php
index b36827c..4b0becd 100644
--- a/includes/content/JsonContent.php
+++ b/includes/content/JsonContent.php
@@ -6,45 +6,70 @@
*
* @author Ori Livneh <[email protected]>
* @author Kunal Mehta <[email protected]>
+ * @author Yuri Astrakhan <yurik !@! wikimedia ! org>
*/
/**
* Represents the content of a JSON content.
* @since 1.24
*/
-class JsonContent extends TextContent {
+class JsonContent extends CodeContent {
+
+ /** @var \Status */
+ private $status;
+
+ /** @var int */
+ private $decodeOpts;
public function __construct( $text, $modelId = CONTENT_MODEL_JSON ) {
parent::__construct( $text, $modelId );
}
/**
- * Decodes the JSON into a PHP associative array.
- * @return array
- */
- public function getJsonData() {
- return FormatJson::decode( $this->getNativeData(), true );
- }
-
- /**
* @return bool Whether content is valid JSON.
*/
public function isValid() {
- return $this->getJsonData() !== null;
+ // It is possible for the valid JSON to be ok but not good,
+ // implying that it decodes ok but did not pass some additional
validation
+ return $this->getJson()->isGood();
+ }
+
+ public function decodeOptions( $options = false ) {
+ if ( $options !== false ) {
+ $this->decodeOpts = $options;
+ }
+ return $this->decodeOpts;
}
/**
- * Pretty-print JSON
- *
- * @return bool|null|string
+ * Decodes JSON content into the PHP data structure.
+ * @deprecated use getJson()
+ * @return array
*/
- public function beautifyJSON() {
- $decoded = FormatJson::decode( $this->getNativeData(), true );
- if ( !is_array( $decoded ) ) {
- return null;
- }
- return FormatJson::encode( $decoded, true );
+ public function getJsonData() {
+ return $this->getJson()->getValue();
+ }
+ /**
+ * Return the status object that will contain parsed data if ok, or the
error otherwise
+ * Note to inheritors: override parseJson() instead of this method
+ * @return Status
+ */
+ public function getJson() {
+ if ( $this->status === null ) {
+ $this->status = $this->parseJson();
+ }
+ return $this->status;
+ }
+
+ /**
+ * Convert native data string into the Status object.
+ * On success, status' value is set to the decoded value.
+ * Derived classes may override this method to add additional validation
+ * @return Status
+ */
+ protected function parseJson() {
+ return FormatJson::parse( $this->getNativeData(),
$this->decodeOptions() );
}
/**
@@ -55,66 +80,30 @@
* @return JsonContent
*/
public function preSaveTransform( Title $title, User $user,
ParserOptions $popts ) {
- return new static( $this->beautifyJSON() );
+ $data = $this->getJson();
+ if ( !$data->isOK() ) {
+ return $this;
+ }
+ // When saving, we are ok to save optimally-encoded,
non-pretty-printed data
+ $newText = FormatJson::encode( $data->getValue(), false,
FormatJson::ALL_OK );
+ if ( $this->getNativeData() === $newText ) {
+ return $this;
+ }
+ $new = new static( $newText, $this->getModel() );
+ $new->decodeOptions( $this->decodeOptions() );
+ return $new;
}
/**
- * Set the HTML and add the appropriate styles
- *
- *
- * @param Title $title
- * @param int $revId
- * @param ParserOptions $options
- * @param bool $generateHtml
- * @param ParserOutput $output
+ * @return string JavaScript wrapped in a <pre> tag.
*/
- protected function fillParserOutput( Title $title, $revId,
- ParserOptions $options, $generateHtml, ParserOutput &$output
- ) {
- if ( $generateHtml ) {
- $output->setText( $this->objectTable(
$this->getJsonData() ) );
- $output->addModuleStyles( 'mediawiki.content.json' );
- } else {
- $output->setText( '' );
- }
- }
- /**
- * Constructs an HTML representation of a JSON object.
- * @param array $mapping
- * @return string HTML
- */
- protected function objectTable( $mapping ) {
- $rows = array();
-
- foreach ( $mapping as $key => $val ) {
- $rows[] = $this->objectRow( $key, $val );
- }
- return Xml::tags( 'table', array( 'class' => 'mw-json' ),
- Xml::tags( 'tbody', array(), join( "\n", $rows ) )
- );
- }
-
- /**
- * Constructs HTML representation of a single key-value pair.
- * @param string $key
- * @param mixed $val
- * @return string HTML.
- */
- protected function objectRow( $key, $val ) {
- $th = Xml::elementClean( 'th', array(), $key );
- if ( is_array( $val ) ) {
- $td = Xml::tags( 'td', array(), self::objectTable( $val
) );
- } else {
- if ( is_string( $val ) ) {
- $val = '"' . $val . '"';
- } else {
- $val = FormatJson::encode( $val );
- }
-
- $td = Xml::elementClean( 'td', array( 'class' =>
'value' ), $val );
- }
-
- return Xml::tags( 'tr', array(), $th . $td );
+ protected function getHtml() {
+ $data = $this->getJson();
+ // Return original data if this is not a valid JSON
+ $text = !$data->isOK()
+ ? $this->getNativeData()
+ : FormatJson::encode( $data->getValue(), true,
FormatJson::UTF8_OK );
+ return $this->codeToPreElement( 'mw-json', $text );
}
}
diff --git a/tests/phpunit/includes/content/JsonContentTest.php
b/tests/phpunit/includes/content/JsonContentTest.php
index 6c77d1a..5f4ab20 100644
--- a/tests/phpunit/includes/content/JsonContentTest.php
+++ b/tests/phpunit/includes/content/JsonContentTest.php
@@ -8,27 +8,32 @@
/**
* @dataProvider provideValidConstruction
+ * @param $text
+ * @param $isValid
+ * @param $expected
*/
- public function testValidConstruct( $text, $modelId, $isValid,
$expected ) {
- $obj = new JsonContent( $text, $modelId );
- $this->assertEquals( $isValid, $obj->isValid() );
- $this->assertEquals( $expected, $obj->getJsonData() );
+ public function testValidConstruct( $text, $isValid, $expected ) {
+ $obj = new JsonContent( $text, CONTENT_MODEL_JSON );
+ $status = $obj->getJson();
+ $this->assertEquals( $isValid, $status->isOK() );
+ $this->assertEquals( $expected, $status->getValue() );
}
public function provideValidConstruction() {
return array(
- array( 'foo', CONTENT_MODEL_JSON, false, null ),
- array( FormatJson::encode( array() ),
CONTENT_MODEL_JSON, true, array() ),
- array( FormatJson::encode( array( 'foo' ) ),
CONTENT_MODEL_JSON, true, array( 'foo' ) ),
+ array( 'foo', false, null ),
+ array( FormatJson::encode( array() ), true, array() ),
+ array( FormatJson::encode( array( 'foo' ) ), true,
array( 'foo' ) ),
);
}
/**
* @dataProvider provideDataToEncode
*/
- public function testBeautifyUsesFormatJson( $data ) {
+ public function testPreSaveTransform( $data ) {
$obj = new JsonContent( FormatJson::encode( $data ) );
- $this->assertEquals( FormatJson::encode( $data, true ),
$obj->beautifyJSON() );
+ $newObj = $obj->preSaveTransform( $this->getMockTitle(),
$this->getMockUser(), $this->getMockParserOptions() );
+ $this->assertTrue( $newObj->equals( new JsonContent(
FormatJson::encode( $data, false, FormatJson::ALL_OK ) ) ) );
}
public function provideDataToEncode() {
@@ -39,15 +44,6 @@
array( array( 'baz' => 'foo', 'bar' ) ),
array( array( 'baz' => 1000, 'bar' ) ),
);
- }
-
- /**
- * @dataProvider provideDataToEncode
- */
- public function testPreSaveTransform( $data ) {
- $obj = new JsonContent( FormatJson::encode( $data ) );
- $newObj = $obj->preSaveTransform( $this->getMockTitle(),
$this->getMockUser(), $this->getMockParserOptions() );
- $this->assertTrue( $newObj->equals( new JsonContent(
FormatJson::encode( $data, true ) ) ) );
}
private function getMockTitle() {
@@ -61,6 +57,7 @@
->disableOriginalConstructor()
->getMock();
}
+
private function getMockParserOptions() {
return $this->getMockBuilder( 'ParserOptions' )
->disableOriginalConstructor()
--
To view, visit https://gerrit.wikimedia.org/r/160575
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idbca6c091d61bf33174110dd3637a9a913e3503b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Yurik <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits