jenkins-bot has submitted this change and it was merged.

Change subject: Factor out extension data manipulation
......................................................................


Factor out extension data manipulation

Change-Id: I1aa83bbbecf6432468739c60a937cde991563157
---
M extension.json
M includes/Hooks.php
A includes/State.php
M includes/Tag/MapFrame.php
M includes/Tag/MapLink.php
M includes/Tag/TagHandler.php
M tests/phpunit/KartographerTest.php
7 files changed, 154 insertions(+), 34 deletions(-)

Approvals:
  Yurik: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/extension.json b/extension.json
index 7d1f9c9..9a0d3cd 100644
--- a/extension.json
+++ b/extension.json
@@ -23,6 +23,7 @@
                "Kartographer\\DataModule": "includes/DataModule.php",
                "Kartographer\\Hooks": "includes/Hooks.php",
                "Kartographer\\SimpleStyleParser": 
"includes/SimpleStyleParser.php",
+               "Kartographer\\State": "includes/State.php",
                "Kartographer\\Tag\\MapFrame": "includes/Tag/MapFrame.php",
                "Kartographer\\Tag\\MapLink": "includes/Tag/MapLink.php",
                "Kartographer\\Tag\\TagHandler": "includes/Tag/TagHandler.php"
diff --git a/includes/Hooks.php b/includes/Hooks.php
index 8343ee5..94a6e66 100644
--- a/includes/Hooks.php
+++ b/includes/Hooks.php
@@ -11,9 +11,10 @@
 
 use Kartographer\Tag\TagHandler;
 use Parser;
+use ParserOutput;
 
 class Hooks {
-       static $tags = [
+       private static $tags = [
                'mapframe' => 'Kartographer\Tag\MapFrame::entryPoint',
                'maplink' => 'Kartographer\Tag\MapLink::entryPoint',
        ];
@@ -59,4 +60,21 @@
                TagHandler::finalParseStep( $parser );
                return true;
        }
+
+       /**
+        * RejectParserCacheValue hook handler. Rejects output with old 
versions of map data
+        * structures. To be enabled at a later date.
+        * @see 
https://www.mediawiki.org/wiki/Manual:Hooks/RejectParserCacheValue
+        * @param ParserOutput $po
+        * @return bool
+        */
+       /*public static function onRejectParserCacheValue( ParserOutput $po ) {
+               // One of these should be prsent in any output with old version 
of data
+               if ( $po->getExtensionData( 'kartographer_valid' )
+                        || $po->getExtensionData( 'kartographer_broken' )
+               ) {
+                       return false;
+               }
+               return true;
+       }*/
 }
diff --git a/includes/State.php b/includes/State.php
new file mode 100644
index 0000000..f90741a
--- /dev/null
+++ b/includes/State.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Kartographer;
+
+use ParserOutput;
+use stdClass;
+
+/**
+ * Stores information about map tags on page in ParserOutput
+ */
+class State {
+       const DATA_KEY = 'kartographer';
+       const VERSION = 1;
+
+       /** @var int Version of this class, for checking after deserialization 
*/
+       private $version = self::VERSION;
+
+       private $valid = false;
+       private $broken = false;
+       private $interactiveGroups = [];
+       private $requestedGroups = [];
+       private $counters;
+       private $data = [];
+
+       /**
+        * Retrieves an instance of self from ParserOutout, if present
+        *
+        * @param ParserOutput $output
+        * @return self|null
+        */
+       public static function getState( ParserOutput $output ) {
+               return $output->getExtensionData( self::DATA_KEY );
+       }
+
+       /**
+        * Retrieves an instance of self from ParserOutput, initializing it 
anew if not present
+        *
+        * @param ParserOutput $output
+        * @return State
+        */
+       public static function getOrCreate( ParserOutput $output ) {
+               $result = self::getState( $output );
+               if ( !$result ) {
+                       $result = new self;
+                       $output->setExtensionData( self::DATA_KEY, $result );
+               }
+
+               return $result;
+       }
+
+       public function hasValidTags() {
+               return $this->valid;
+       }
+
+       public function setValidTags() {
+               $this->valid = true;
+       }
+
+       public function hasBrokenTags() {
+               return $this->broken;
+       }
+
+       public function setBrokenTags() {
+               $this->broken = true;
+       }
+
+       public function addInteractiveGroups( array $groups ) {
+               $this->interactiveGroups += array_flip( $groups );
+       }
+
+       public function getInteractiveGroups() {
+               return array_keys( $this->interactiveGroups );
+       }
+
+       public function addRequestedGroups( array $groups ) {
+               $this->requestedGroups += array_flip( $groups );
+       }
+
+       public function getRequestedGroups() {
+               return $this->requestedGroups;
+       }
+
+       public function getCounters() {
+               return $this->counters ?: new stdClass();
+       }
+
+       public function setCounters( stdClass $counters ) {
+               $this->counters = $counters;
+       }
+
+       public function addData( $key, $data ) {
+               $this->data = $this->data ?: new stdClass();
+               if ( property_exists( $this->data, $key ) ) {
+                       $this->data->$key = array_merge( $this->data->$key, 
$data );
+               } else {
+                       $this->data->$key = $data;
+               }
+       }
+
+       public function getData() {
+               return $this->data;
+       }
+}
diff --git a/includes/Tag/MapFrame.php b/includes/Tag/MapFrame.php
index 7d9fa27..f84cf7c 100644
--- a/includes/Tag/MapFrame.php
+++ b/includes/Tag/MapFrame.php
@@ -103,10 +103,7 @@
                                                FormatJson::ALL_OK );
                                }
 
-                               $groups = $output->getExtensionData( 
'kartographer_interact' );
-                               $groups = $groups ?: [];
-                               $groups = array_merge( $groups, 
$this->showGroups );
-                               $output->setExtensionData( 
'kartographer_interact', $groups );
+                               $this->state->addInteractiveGroups( 
$this->showGroups );
 
                                return Html::rawElement( 'div', $attrs );
                                break;
diff --git a/includes/Tag/MapLink.php b/includes/Tag/MapLink.php
index 7a9a2b2..65c9390 100644
--- a/includes/Tag/MapLink.php
+++ b/includes/Tag/MapLink.php
@@ -22,10 +22,6 @@
        protected function render() {
                $output = $this->parser->getOutput();
                $output->addModules( 'ext.kartographer.link' );
-               $interact = $output->getExtensionData( 'kartographer_interact' 
);
-               if ( $interact === null ) {
-                       $output->setExtensionData( 'kartographer_interact', [] 
);
-               }
 
                // @todo: Mapbox markers don't support localized numbers yet
                $text = $this->getText( 'text', null, '/\S+/' );
diff --git a/includes/Tag/TagHandler.php b/includes/Tag/TagHandler.php
index 695c50d..f0ba225 100644
--- a/includes/Tag/TagHandler.php
+++ b/includes/Tag/TagHandler.php
@@ -13,6 +13,7 @@
 use FormatJson;
 use Html;
 use Kartographer\SimpleStyleParser;
+use Kartographer\State;
 use Language;
 use Parser;
 use ParserOutput;
@@ -63,6 +64,9 @@
        /** @var PPFrame */
        protected $frame;
 
+       /** @var State */
+       protected $state;
+
        /** @var stdClass */
        protected $markerProperties;
 
@@ -107,6 +111,7 @@
                $this->frame = $frame;
                $output = $parser->getOutput();
                $output->addModuleStyles( 'ext.kartographer.style' );
+               $this->state = State::getOrCreate( $output );
 
                $this->status = Status::newGood();
                $this->args = $args;
@@ -121,7 +126,7 @@
 
                $this->saveData( $output );
 
-               $output->setExtensionData( 'kartographer_valid', true );
+               $this->state->setValidTags();
 
                return $this->render();
        }
@@ -241,9 +246,7 @@
 
 
        protected function saveData( ParserOutput $output ) {
-               $requestedGroups = $output->getExtensionData( 
'kartographer_requested' ) ?: [];
-               $requestedGroups = array_merge( $requestedGroups, 
$this->showGroups );
-               $output->setExtensionData( 'kartographer_requested', 
$requestedGroups );
+               $this->state->addRequestedGroups( $this->showGroups );
 
                if ( !$this->geometries ) {
                        return;
@@ -253,12 +256,12 @@
 
                // For all GeoJSON items whose marker-symbol value begins with 
'-counter' and '-letter',
                // recursively replace them with an automatically incremented 
marker icon.
-               $counters = $output->getExtensionData( 'kartographer_counters' 
) ?: new stdClass();
+               $counters = $this->state->getCounters();
                $marker = SimpleStyleParser::doCountersRecursive( 
$this->geometries, $counters );
                if ( $marker ) {
                        list( $this->counter, $this->markerProperties ) = 
$marker;
                }
-               $output->setExtensionData( 'kartographer_counters', $counters );
+               $this->state->setCounters( $counters );
 
                if ( $this->groupName === null ) {
                        $group = '_' . sha1( FormatJson::encode( 
$this->geometries, false, FormatJson::ALL_OK ) );
@@ -269,13 +272,7 @@
                        $group = $this->groupName;
                }
 
-               $data = $output->getExtensionData( 'kartographer_data' ) ?: new 
stdClass();
-               if ( isset( $data->$group ) ) {
-                       $data->$group = array_merge( $data->$group, 
$this->geometries );
-               } else {
-                       $data->$group = $this->geometries;
-               }
-               $output->setExtensionData( 'kartographer_data', $data );
+               $this->state->addData( $group, $this->geometries );
        }
 
        /**
@@ -284,22 +281,27 @@
         */
        public static function finalParseStep( Parser $parser ) {
                $output = $parser->getOutput();
+               $state = State::getState( $output );
 
-               $data = $output->getExtensionData( 'kartographer_data' );
+               if ( !$state ) {
+                       return;
+               }
+
+               $data = $state->getData();
                if ( $data ) {
                        $json = FormatJson::encode( $data, false, 
FormatJson::ALL_OK );
                        $output->setProperty( 'kartographer', gzencode( $json ) 
);
                }
 
-               if ( $output->getExtensionData( 'kartographer_broken' ) ) {
+               if ( $state->hasBrokenTags() ) {
                        $output->addTrackingCategory( 
'kartographer-broken-category', $parser->getTitle() );
                }
-               if ( $output->getExtensionData( 'kartographer_valid' ) ) {
+               if ( $state->hasValidTags() ) {
                        $output->addTrackingCategory( 
'kartographer-tracking-category', $parser->getTitle() );
                }
 
-               $interact = $output->getExtensionData( 'kartographer_interact' 
) ?: [];
-               $requested = $output->getExtensionData( 
'kartographer_requested' ) ?: [];
+               $interact = $state->getInteractiveGroups();
+               $requested = $state->getRequestedGroups();
                if ( $interact || $requested ) {
                        $interact = array_flip( $interact );
                        $liveData = array_intersect_key( (array)$data, 
$interact );
@@ -319,7 +321,7 @@
         * @throws Exception
         */
        private function reportError() {
-               $this->parser->getOutput()->setExtensionData( 
'kartographer_broken', true );
+               $this->state->setBrokenTags();
                $errors = array_merge( $this->status->getErrorsByType( 'error' 
),
                        $this->status->getErrorsByType( 'warning' )
                );
diff --git a/tests/phpunit/KartographerTest.php 
b/tests/phpunit/KartographerTest.php
index e2cfc35..7fe468f 100644
--- a/tests/phpunit/KartographerTest.php
+++ b/tests/phpunit/KartographerTest.php
@@ -1,6 +1,7 @@
 <?php
 namespace Kartographer\Tests;
 
+use Kartographer\State;
 use MediaWikiTestCase;
 use Parser;
 use ParserOptions;
@@ -40,18 +41,20 @@
         */
        public function testTagData( $expected, $input, $message ) {
                $output = $this->parse( $input );
+               $state = State::getState( $output );
 
                if ( $expected === false ) {
-                       $this->assertTrue( $output->getExtensionData( 
'kartographer_broken' ), $message . ' Parse is expected to fail' );
+                       $this->assertTrue( $state->hasBrokenTags(), $message . 
' Parse is expected to fail' );
                        $this->assertTrue( $this->hasTrackingCategory( $output, 
'kartographer-broken-category' ), $message . ' Category for failed maps should 
be added' );
                        return;
                }
-               $this->assertFalse( !!$output->getExtensionData( 
'kartographer_broken' ), $message . ' Parse is expected to succeed' );
+               $this->assertFalse( $state->hasBrokenTags(), $message . ' Parse 
is expected to succeed' );
+               $this->assertTrue( $state->hasValidTags(), $message . ' State 
is expected to have valid tags' );
                $this->assertFalse( $this->hasTrackingCategory( $output, 
'kartographer-broken-category' ), $message . ' No tracking category' );
 
                $expected = json_encode( json_decode( $expected ) ); // 
Normalize JSON
 
-               $this->assertEquals( $expected, json_encode( 
$output->getExtensionData( 'kartographer_data' ) ), $message );
+               $this->assertEquals( $expected, json_encode( $state->getData() 
), $message );
        }
 
        public function provideTagData() {
@@ -104,8 +107,8 @@
                                "description":"<a 
href=\"\/w\/index.php?title=Link_to_nowhere&amp;action=edit&amp;redlink=1\" 
class=\"new\" title=\"Link to nowhere (page does not exist)\">Link to 
nowhere<\/a>","marker-symbol":"1"}}
                        ]}';
                return [
-                       [ 'null', '<mapframe width=700 height=400 zoom=13 
longitude=-122.3988 latitude=37.8013/>', '<mapframe> without JSON' ],
-                       [ 'null', '<mapframe width=700 height=400 zoom=13 
longitude=-122.3988 latitude=37.8013></mapframe>', '<mapframe> without JSON 2' 
],
+                       [ '[]', '<mapframe width=700 height=400 zoom=13 
longitude=-122.3988 latitude=37.8013/>', '<mapframe> without JSON' ],
+                       [ '[]', '<mapframe width=700 height=400 zoom=13 
longitude=-122.3988 latitude=37.8013></mapframe>', '<mapframe> without JSON 2' 
],
                        [ 
"{\"_4622d19afa2e6480c327846395ed932ba6fa56d4\":[$validJson]}", "<mapframe 
width=700 height=400 zoom=13 longitude=-122.3988 
latitude=37.8013>$validJson</mapframe>", '<mapframe> with GeoJSON' ],
                        [ 
"{\"_4622d19afa2e6480c327846395ed932ba6fa56d4\":[$validJson]}", "<mapframe 
width=700 height=400 zoom=13 longitude=-122.3988 
latitude=37.8013>[$validJson]</mapframe>", '<mapframe> with GeoJSON array' ],
                        [ false, '<mapframe width=700 height=400 zoom=13 
longitude=-122.3988 latitude=37.8013>123</mapframe>', 'Invalid JSON' ],
@@ -129,7 +132,7 @@
                        [ $wikitextJsonParsed, "<maplink zoom=13 
longitude=-122.3988 latitude=37.8013>[{$this->wikitextJson}]</maplink>", 
'<maplink> with parsable text and description' ],
 
                        // Bugs
-                       [ 'null', "<maplink zoom=13 longitude=-122.3988 
latitude=37.8013>\t\r\n </maplink>", 'T127345: whitespace-only tag content, 
<maplink>' ],
+                       [ '[]', "<maplink zoom=13 longitude=-122.3988 
latitude=37.8013>\t\r\n </maplink>", 'T127345: whitespace-only tag content, 
<maplink>' ],
                        [ $xssJsonSanitized, "<maplink zoom=13 longitude=10 
latitude=20>$xssJson</maplink>", 'T134719: XSS via __proto__' ],
                ];
        }

-- 
To view, visit https://gerrit.wikimedia.org/r/297110
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I1aa83bbbecf6432468739c60a937cde991563157
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/Kartographer
Gerrit-Branch: master
Gerrit-Owner: MaxSem <[email protected]>
Gerrit-Reviewer: MaxSem <[email protected]>
Gerrit-Reviewer: Yurik <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to