Better way for extensions to add to ParserOutput.
authordaniel <daniel.kinzler@wikimedia.de>
Tue, 22 Jan 2013 11:59:23 +0000 (12:59 +0100)
committerdaniel <daniel.kinzler@wikimedia.de>
Wed, 30 Jan 2013 11:45:47 +0000 (12:45 +0100)
Extensions sometimes need to stash information in the ParserOutput
for later use. This change provides a clean way to do that.

Change-Id: I8bc571d13c9a70bb71430862c2ab679ff1947126

includes/parser/ParserOutput.php
tests/phpunit/includes/parser/ParserOutputTest.php

index f32d5b6..53b6293 100644 (file)
@@ -51,6 +51,7 @@ class ParserOutput extends CacheTime {
                private $mIndexPolicy = '';       # 'index' or 'noindex'?  Any other value will result in no change.
                private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys)
                private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else.
+               private $mExtensionData = array(); # extra data used by extensions
 
        const EDITSECTION_REGEX = '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#';
 
@@ -370,15 +371,31 @@ class ParserOutput extends CacheTime {
         *     Wikimedia Commons.
         *     This is not actually implemented, yet but would be pretty cool.
         *
-        * Do not use setProperty() to set a property which is only used in a
-        * context where the ParserOutput object itself is already available, for
-        * example a normal page view. There is no need to save such a property
+        * @note: Do not use setProperty() to set a property which is only used
+        * in a context where the ParserOutput object itself is already available,
+        * for example a normal page view. There is no need to save such a property
         * in the database since it the text is already parsed. You can just hook
         * OutputPageParserOutput and get your data out of the ParserOutput object.
         *
-        * If you are writing an extension where you want to set
-        * a property in the parser which is used by an OutputPageParserOutput hook,
-        * just use a custom variable within the ParserOutput object:
+        * If you are writing an extension where you want to set a property in the
+        * parser which is used by an OutputPageParserOutput hook, you have to
+        * associate the extension data directly with the ParserOutput object.
+        * Since MediaWiki 1.21, you can use setExtensionData() to do this:
+        *
+        * @par Example:
+        * @code
+        *    $parser->getOutput()->setExtensionData( 'my_ext_foo', '...' );
+        * @endcode
+        *
+        * And then later, in OutputPageParserOutput or similar:
+        *
+        * @par Example:
+        * @code
+        *    $output->getExtensionData( 'my_ext_foo' );
+        * @endcode
+        *
+        * In MediaWiki 1.20 and older, you have to use a custom member variable
+        * within the ParserOutput object:
         *
         * @par Example:
         * @code
@@ -460,4 +477,72 @@ class ParserOutput extends CacheTime {
                return array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) );
        }
 
+       /**
+        * Attaches arbitrary data to this ParserObject. This can be used to store some information in
+        * the ParserOutput object for later use during page output. The data will be cached along with
+        * the ParserOutput object, but unlike data set using setProperty(), it is not recorded in the
+        * database.
+        *
+        * This method is provided to overcome the unsafe practice of attaching extra information to a
+        * ParserObject by directly assigning member variables.
+        *
+        * To use setExtensionData() to pass extension information from a hook inside the parser to a
+        * hook in the page output, use this in the parser hook:
+        *
+        * @par Example:
+        * @code
+        *    $parser->getOutput()->setExtensionData( 'my_ext_foo', '...' );
+        * @endcode
+        *
+        * And then later, in OutputPageParserOutput or similar:
+        *
+        * @par Example:
+        * @code
+        *    $output->getExtensionData( 'my_ext_foo' );
+        * @endcode
+        *
+        * In MediaWiki 1.20 and older, you have to use a custom member variable
+        * within the ParserOutput object:
+        *
+        * @par Example:
+        * @code
+        *    $parser->getOutput()->my_ext_foo = '...';
+        * @endcode
+        *
+        * @since 1.21
+        *
+        * @param string $key The key for accessing the data. Extensions should take care to avoid
+        *               conflicts in naming keys. It is suggested to use the extension's name as a
+        *               prefix.
+        *
+        * @param mixed $value The value to set. Setting a value to null is equivalent to removing
+        *              the value.
+        */
+       public function setExtensionData( $key, $value ) {
+               if ( $value === null ) {
+                       unset( $this->mExtensionData[$key] );
+               } else {
+                       $this->mExtensionData[$key] = $value;
+               }
+       }
+
+       /**
+        * Gets extensions data previously attached to this ParserOutput using setExtensionData().
+        * Typically, such data would be set while parsing the page, e.g. by a parser function.
+        *
+        * @since 1.21
+        *
+        * @param string $key The key to look up.
+        *
+        * @return mixed The value previously set for the given key using setExtensionData( $key ),
+        *         or null if no value was set for this key.
+        */
+       public function getExtensionData( $key ) {
+               if ( isset( $this->mExtensionData[$key] ) ) {
+                       return $this->mExtensionData[$key];
+               }
+
+               return null;
+       }
+
 }
index 2244fdb..68f77ab 100644 (file)
@@ -35,4 +35,21 @@ class ParserOutputTest extends MediaWikiTestCase {
 
                $this->assertEquals( $shouldMatch, ParserOutput::isLinkInternal( $server, $url ) );
        }
+
+       public function testExtensionData() {
+               $po = new ParserOutput();
+
+               $po->setExtensionData( "one", "Foo" );
+
+               $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
+               $this->assertNull( $po->getExtensionData( "spam" ) );
+
+               $po->setExtensionData( "two", "Bar" );
+               $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
+               $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
+
+               $po->setExtensionData( "one", null );
+               $this->assertNull( $po->getExtensionData( "one" ) );
+               $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
+       }
 }