]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - includes/content/JsonContent.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / includes / content / JsonContent.php
diff --git a/includes/content/JsonContent.php b/includes/content/JsonContent.php
new file mode 100644 (file)
index 0000000..2b94f3f
--- /dev/null
@@ -0,0 +1,251 @@
+<?php
+/**
+ * JSON Content Model
+ *
+ * @file
+ *
+ * @author Ori Livneh <ori@wikimedia.org>
+ * @author Kunal Mehta <legoktm@gmail.com>
+ */
+
+/**
+ * Represents the content of a JSON content.
+ * @since 1.24
+ */
+class JsonContent extends TextContent {
+
+       /**
+        * @since 1.25
+        * @var Status
+        */
+       protected $jsonParse;
+
+       /**
+        * @param string $text JSON
+        * @param string $modelId
+        */
+       public function __construct( $text, $modelId = CONTENT_MODEL_JSON ) {
+               parent::__construct( $text, $modelId );
+       }
+
+       /**
+        * Decodes the JSON into a PHP associative array.
+        *
+        * @deprecated since 1.25 Use getData instead.
+        * @return array|null
+        */
+       public function getJsonData() {
+               wfDeprecated( __METHOD__, '1.25' );
+               return FormatJson::decode( $this->getNativeData(), true );
+       }
+
+       /**
+        * Decodes the JSON string.
+        *
+        * Note that this parses it without casting objects to associative arrays.
+        * Objects and arrays are kept as distinguishable types in the PHP values.
+        *
+        * @return Status
+        */
+       public function getData() {
+               if ( $this->jsonParse === null ) {
+                       $this->jsonParse = FormatJson::parse( $this->getNativeData() );
+               }
+               return $this->jsonParse;
+       }
+
+       /**
+        * @return bool Whether content is valid.
+        */
+       public function isValid() {
+               return $this->getData()->isGood();
+       }
+
+       /**
+        * Pretty-print JSON.
+        *
+        * If called before validation, it may return JSON "null".
+        *
+        * @return string
+        */
+       public function beautifyJSON() {
+               return FormatJson::encode( $this->getData()->getValue(), true, FormatJson::UTF8_OK );
+       }
+
+       /**
+        * Beautifies JSON prior to save.
+        *
+        * @param Title $title Title
+        * @param User $user User
+        * @param ParserOptions $popts
+        * @return JsonContent
+        */
+       public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
+               // FIXME: WikiPage::doEditContent invokes PST before validation. As such, native data
+               // may be invalid (though PST result is discarded later in that case).
+               if ( !$this->isValid() ) {
+                       return $this;
+               }
+
+               return new static( self::normalizeLineEndings( $this->beautifyJSON() ) );
+       }
+
+       /**
+        * Set the HTML and add the appropriate styles.
+        *
+        * @param Title $title
+        * @param int $revId
+        * @param ParserOptions $options
+        * @param bool $generateHtml
+        * @param ParserOutput &$output
+        */
+       protected function fillParserOutput( Title $title, $revId,
+               ParserOptions $options, $generateHtml, ParserOutput &$output
+       ) {
+               // FIXME: WikiPage::doEditContent generates parser output before validation.
+               // As such, native data may be invalid (though output is discarded later in that case).
+               if ( $generateHtml && $this->isValid() ) {
+                       $output->setText( $this->rootValueTable( $this->getData()->getValue() ) );
+                       $output->addModuleStyles( 'mediawiki.content.json' );
+               } else {
+                       $output->setText( '' );
+               }
+       }
+
+       /**
+        * Construct HTML table representation of any JSON value.
+        *
+        * See also valueCell, which is similar.
+        *
+        * @param mixed $val
+        * @return string HTML.
+        */
+       protected function rootValueTable( $val ) {
+               if ( is_object( $val ) ) {
+                       return $this->objectTable( $val );
+               }
+
+               if ( is_array( $val ) ) {
+                       // Wrap arrays in another array so that they're visually boxed in a container.
+                       // Otherwise they are visually indistinguishable from a single value.
+                       return $this->arrayTable( [ $val ] );
+               }
+
+               return Html::rawElement( 'table', [ 'class' => 'mw-json mw-json-single-value' ],
+                       Html::rawElement( 'tbody', [],
+                               Html::rawElement( 'tr', [],
+                                       Html::element( 'td', [], $this->primitiveValue( $val ) )
+                               )
+                       )
+               );
+       }
+
+       /**
+        * Create HTML table representing a JSON object.
+        *
+        * @param stdClass $mapping
+        * @return string HTML
+        */
+       protected function objectTable( $mapping ) {
+               $rows = [];
+               $empty = true;
+
+               foreach ( $mapping as $key => $val ) {
+                       $rows[] = $this->objectRow( $key, $val );
+                       $empty = false;
+               }
+               if ( $empty ) {
+                       $rows[] = Html::rawElement( 'tr', [],
+                               Html::element( 'td', [ 'class' => 'mw-json-empty' ],
+                                       wfMessage( 'content-json-empty-object' )->text()
+                               )
+                       );
+               }
+               return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
+                       Html::rawElement( 'tbody', [], implode( '', $rows ) )
+               );
+       }
+
+       /**
+        * Create HTML table row representing one object property.
+        *
+        * @param string $key
+        * @param mixed $val
+        * @return string HTML.
+        */
+       protected function objectRow( $key, $val ) {
+               $th = Html::element( 'th', [], $key );
+               $td = $this->valueCell( $val );
+               return Html::rawElement( 'tr', [], $th . $td );
+       }
+
+       /**
+        * Create HTML table representing a JSON array.
+        *
+        * @param array $mapping
+        * @return string HTML
+        */
+       protected function arrayTable( $mapping ) {
+               $rows = [];
+               $empty = true;
+
+               foreach ( $mapping as $val ) {
+                       $rows[] = $this->arrayRow( $val );
+                       $empty = false;
+               }
+               if ( $empty ) {
+                       $rows[] = Html::rawElement( 'tr', [],
+                               Html::element( 'td', [ 'class' => 'mw-json-empty' ],
+                                       wfMessage( 'content-json-empty-array' )->text()
+                               )
+                       );
+               }
+               return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
+                       Html::rawElement( 'tbody', [], implode( "\n", $rows ) )
+               );
+       }
+
+       /**
+        * Create HTML table row representing the value in an array.
+        *
+        * @param mixed $val
+        * @return string HTML.
+        */
+       protected function arrayRow( $val ) {
+               $td = $this->valueCell( $val );
+               return Html::rawElement( 'tr', [], $td );
+       }
+
+       /**
+        * Construct HTML table cell representing any JSON value.
+        *
+        * @param mixed $val
+        * @return string HTML.
+        */
+       protected function valueCell( $val ) {
+               if ( is_object( $val ) ) {
+                       return Html::rawElement( 'td', [], $this->objectTable( $val ) );
+               }
+
+               if ( is_array( $val ) ) {
+                       return Html::rawElement( 'td', [], $this->arrayTable( $val ) );
+               }
+
+               return Html::element( 'td', [ 'class' => 'value' ], $this->primitiveValue( $val ) );
+       }
+
+       /**
+        * Construct text representing a JSON primitive value.
+        *
+        * @param mixed $val
+        * @return string Text.
+        */
+       protected function primitiveValue( $val ) {
+               if ( is_string( $val ) ) {
+                       // Don't FormatJson::encode for strings since we want quotes
+                       // and new lines to render visually instead of escaped.
+                       return '"' . $val . '"';
+               }
+               return FormatJson::encode( $val );
+       }
+}