MagicWordFactory to replace MagicWord static members/methods
authorAryeh Gregor <ayg@aryeh.name>
Tue, 24 Jul 2018 16:44:09 +0000 (19:44 +0300)
committerAryeh Gregor <ayg@aryeh.name>
Mon, 30 Jul 2018 18:20:43 +0000 (21:20 +0300)
Static members of MagicWord have been removed.

Static methods are soft-deprecated and forward to the factory.  They
will be hard-deprecated when all callers are removed from core.

MagicWord::clearCache() has been removed.  Instead, call
resetServiceForTesting( 'MagicWordFactory' ) on your MediaWikiServices
object.

Change-Id: Ie061fe90f9b9eca0cbf7e8199d9ca325c464867a
Bug: T200247

RELEASE-NOTES-1.32
autoload.php
includes/MagicWord.php
includes/MagicWordFactory.php [new file with mode: 0644]
includes/MediaWikiServices.php
includes/ServiceWiring.php
tests/parser/ParserTestRunner.php
tests/phpunit/includes/ExtraParserTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/content/WikitextContentHandlerTest.php

index bbcd6c2..c5e9a67 100644 (file)
@@ -209,6 +209,11 @@ because of Phabricator reports.
   * getItemsData: Use getItems instead and get the data property
 * Two OutputPage methods, addMetadataLink() and getMetadataAttribute(), were
   removed.  Use addLink() instead.
+* All MagicWord static member variables have been removed.  Use appropriate
+  hooks or MagicWordFactory methods instead.
+* MagicWord::clearCache() has been removed.  Instead, create a new
+  MagicWordFactory, such as by calling
+  resetServiceForTesting( 'MagicWordFactory' ) on a MediaWikiServices.
 
 === Deprecations in 1.32 ===
 * Use of a StartProfiler.php file is deprecated in favour of placing
@@ -304,6 +309,8 @@ because of Phabricator reports.
 * The $wgExternalDiffEngine value 'wikidiff2' is deprecated. To use wikidiff2
   just enable the PHP extension, and it will be autodetected.
 * The wfUseMW function, soft-deprecated in 1.26, is now hard deprecated.
+* All MagicWord static methods are now deprecated.  Use the MagicWordFactory
+  methods instead.
 
 === Other changes in 1.32 ===
 * (T198811) The following tables have had their UNIQUE indexes turned into
index 7588060..b5b5c52 100644 (file)
@@ -832,6 +832,7 @@ $wgAutoloadLocalClasses = [
        'MachineReadableRCFeedFormatter' => __DIR__ . '/includes/rcfeed/MachineReadableRCFeedFormatter.php',
        'MagicWord' => __DIR__ . '/includes/MagicWord.php',
        'MagicWordArray' => __DIR__ . '/includes/MagicWordArray.php',
+       'MagicWordFactory' => __DIR__ . '/includes/MagicWordFactory.php',
        'MailAddress' => __DIR__ . '/includes/mail/MailAddress.php',
        'MainConfigDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'MaintainableDBConnRef' => __DIR__ . '/includes/libs/rdbms/database/MaintainableDBConnRef.php',
index 9cef700..a193c9f 100644 (file)
  * @ingroup Parser
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * This class encapsulates "magic words" such as "#redirect", __NOTOC__, etc.
  *
  * @par Usage:
  * @code
- *     if (MagicWord::get( 'redirect' )->match( $text ) ) {
+ *     if ( $magicWordFactory->get( 'redirect' )->match( $text ) ) {
  *       // some code
  *     }
  * @endcode
  *
- * Possible future improvements:
- *   * Simultaneous searching for a number of magic words
- *   * MagicWord::$mObjects in shared memory
- *
  * Please avoid reading the data out of one of these objects and then writing
  * special case code. If possible, add another match()-like function here.
  *
@@ -92,170 +90,12 @@ class MagicWord {
        /** @var bool */
        private $mFound = false;
 
-       /** @var bool */
-       public static $mVariableIDsInitialised = false;
-
-       /** @var string[] */
-       public static $mVariableIDs = [
-               '!',
-               'currentmonth',
-               'currentmonth1',
-               'currentmonthname',
-               'currentmonthnamegen',
-               'currentmonthabbrev',
-               'currentday',
-               'currentday2',
-               'currentdayname',
-               'currentyear',
-               'currenttime',
-               'currenthour',
-               'localmonth',
-               'localmonth1',
-               'localmonthname',
-               'localmonthnamegen',
-               'localmonthabbrev',
-               'localday',
-               'localday2',
-               'localdayname',
-               'localyear',
-               'localtime',
-               'localhour',
-               'numberofarticles',
-               'numberoffiles',
-               'numberofedits',
-               'articlepath',
-               'pageid',
-               'sitename',
-               'server',
-               'servername',
-               'scriptpath',
-               'stylepath',
-               'pagename',
-               'pagenamee',
-               'fullpagename',
-               'fullpagenamee',
-               'namespace',
-               'namespacee',
-               'namespacenumber',
-               'currentweek',
-               'currentdow',
-               'localweek',
-               'localdow',
-               'revisionid',
-               'revisionday',
-               'revisionday2',
-               'revisionmonth',
-               'revisionmonth1',
-               'revisionyear',
-               'revisiontimestamp',
-               'revisionuser',
-               'revisionsize',
-               'subpagename',
-               'subpagenamee',
-               'talkspace',
-               'talkspacee',
-               'subjectspace',
-               'subjectspacee',
-               'talkpagename',
-               'talkpagenamee',
-               'subjectpagename',
-               'subjectpagenamee',
-               'numberofusers',
-               'numberofactiveusers',
-               'numberofpages',
-               'currentversion',
-               'rootpagename',
-               'rootpagenamee',
-               'basepagename',
-               'basepagenamee',
-               'currenttimestamp',
-               'localtimestamp',
-               'directionmark',
-               'contentlanguage',
-               'pagelanguage',
-               'numberofadmins',
-               'cascadingsources',
-       ];
-
-       /** Array of caching hints for ParserCache
-        * @var array [ string => int ]
-        */
-       public static $mCacheTTLs = [
-               'currentmonth' => 86400,
-               'currentmonth1' => 86400,
-               'currentmonthname' => 86400,
-               'currentmonthnamegen' => 86400,
-               'currentmonthabbrev' => 86400,
-               'currentday' => 3600,
-               'currentday2' => 3600,
-               'currentdayname' => 3600,
-               'currentyear' => 86400,
-               'currenttime' => 3600,
-               'currenthour' => 3600,
-               'localmonth' => 86400,
-               'localmonth1' => 86400,
-               'localmonthname' => 86400,
-               'localmonthnamegen' => 86400,
-               'localmonthabbrev' => 86400,
-               'localday' => 3600,
-               'localday2' => 3600,
-               'localdayname' => 3600,
-               'localyear' => 86400,
-               'localtime' => 3600,
-               'localhour' => 3600,
-               'numberofarticles' => 3600,
-               'numberoffiles' => 3600,
-               'numberofedits' => 3600,
-               'currentweek' => 3600,
-               'currentdow' => 3600,
-               'localweek' => 3600,
-               'localdow' => 3600,
-               'numberofusers' => 3600,
-               'numberofactiveusers' => 3600,
-               'numberofpages' => 3600,
-               'currentversion' => 86400,
-               'currenttimestamp' => 3600,
-               'localtimestamp' => 3600,
-               'pagesinnamespace' => 3600,
-               'numberofadmins' => 3600,
-               'numberingroup' => 3600,
-       ];
-
-       /** @var string[] */
-       public static $mDoubleUnderscoreIDs = [
-               'notoc',
-               'nogallery',
-               'forcetoc',
-               'toc',
-               'noeditsection',
-               'newsectionlink',
-               'nonewsectionlink',
-               'hiddencat',
-               'index',
-               'noindex',
-               'staticredirect',
-               'notitleconvert',
-               'nocontentconvert',
-       ];
-
-       /** @var string[] */
-       public static $mSubstIDs = [
-               'subst',
-               'safesubst',
-       ];
-
-       /** @var array [ string => MagicWord ] */
-       public static $mObjects = [];
-
-       /** @var MagicWordArray */
-       public static $mDoubleUnderscoreArray = null;
-
        /**#@-*/
 
        /**
         * Create a new MagicWord object
         *
-        * Use factory instead: MagicWord::get
+        * Use factory instead: MagicWordFactory::get
         *
         * @param string|null $id The internal name of the magic word
         * @param string[]|string $syn synonyms for the magic word
@@ -273,36 +113,29 @@ class MagicWord {
         * @param string $id The internal name of the magic word
         *
         * @return MagicWord
+        * @deprecated since 1.32, use MagicWordFactory::get
         */
-       public static function &get( $id ) {
-               if ( !isset( self::$mObjects[$id] ) ) {
-                       $mw = new MagicWord();
-                       $mw->load( $id );
-                       self::$mObjects[$id] = $mw;
-               }
-               return self::$mObjects[$id];
+       public static function get( $id ) {
+               return MediaWikiServices::getInstance()->getMagicWordFactory()->get( $id );
        }
 
        /**
         * Get an array of parser variable IDs
         *
         * @return string[]
+        * @deprecated since 1.32, use MagicWordFactory::getVariableIDs
         */
        public static function getVariableIDs() {
-               if ( !self::$mVariableIDsInitialised ) {
-                       # Get variable IDs
-                       Hooks::run( 'MagicWordwgVariableIDs', [ &self::$mVariableIDs ] );
-                       self::$mVariableIDsInitialised = true;
-               }
-               return self::$mVariableIDs;
+               return MediaWikiServices::getInstance()->getMagicWordFactory()->getVariableIDs();
        }
 
        /**
         * Get an array of parser substitution modifier IDs
         * @return string[]
+        * @deprecated since 1.32, use MagicWordFactory::getSubstIDs
         */
        public static function getSubstIDs() {
-               return self::$mSubstIDs;
+               return MediaWikiServices::getInstance()->getMagicWordFactory()->getSubstIDs();
        }
 
        /**
@@ -310,34 +143,20 @@ class MagicWord {
         *
         * @param string $id
         * @return int
+        * @deprecated since 1.32, use MagicWordFactory::getCacheTTL
         */
        public static function getCacheTTL( $id ) {
-               if ( array_key_exists( $id, self::$mCacheTTLs ) ) {
-                       return self::$mCacheTTLs[$id];
-               } else {
-                       return -1;
-               }
+               return MediaWikiServices::getInstance()->getMagicWordFactory()->getCacheTTL( $id );
        }
 
        /**
         * Get a MagicWordArray of double-underscore entities
         *
         * @return MagicWordArray
+        * @deprecated since 1.32, use MagicWordFactory::getDoubleUnderscoreArray
         */
        public static function getDoubleUnderscoreArray() {
-               if ( is_null( self::$mDoubleUnderscoreArray ) ) {
-                       Hooks::run( 'GetDoubleUnderscoreIDs', [ &self::$mDoubleUnderscoreIDs ] );
-                       self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs );
-               }
-               return self::$mDoubleUnderscoreArray;
-       }
-
-       /**
-        * Clear the self::$mObjects variable
-        * For use in parser tests
-        */
-       public static function clearCache() {
-               self::$mObjects = [];
+               return MediaWikiServices::getInstance()->getMagicWordFactory()->getDoubleUnderscoreArray();
        }
 
        /**
diff --git a/includes/MagicWordFactory.php b/includes/MagicWordFactory.php
new file mode 100644 (file)
index 0000000..11ed0a7
--- /dev/null
@@ -0,0 +1,261 @@
+<?php
+/**
+ * See docs/magicword.txt.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * A factory that stores information about MagicWords, and creates them on demand with caching.
+ *
+ * Possible future improvements:
+ *   * Simultaneous searching for a number of magic words
+ *   * $mObjects in shared memory
+ *
+ * @since 1.32
+ * @ingroup Parser
+ */
+class MagicWordFactory {
+       /**#@-*/
+
+       /** @var bool */
+       private $mVariableIDsInitialised = false;
+
+       /** @var string[] */
+       private $mVariableIDs = [
+               '!',
+               'currentmonth',
+               'currentmonth1',
+               'currentmonthname',
+               'currentmonthnamegen',
+               'currentmonthabbrev',
+               'currentday',
+               'currentday2',
+               'currentdayname',
+               'currentyear',
+               'currenttime',
+               'currenthour',
+               'localmonth',
+               'localmonth1',
+               'localmonthname',
+               'localmonthnamegen',
+               'localmonthabbrev',
+               'localday',
+               'localday2',
+               'localdayname',
+               'localyear',
+               'localtime',
+               'localhour',
+               'numberofarticles',
+               'numberoffiles',
+               'numberofedits',
+               'articlepath',
+               'pageid',
+               'sitename',
+               'server',
+               'servername',
+               'scriptpath',
+               'stylepath',
+               'pagename',
+               'pagenamee',
+               'fullpagename',
+               'fullpagenamee',
+               'namespace',
+               'namespacee',
+               'namespacenumber',
+               'currentweek',
+               'currentdow',
+               'localweek',
+               'localdow',
+               'revisionid',
+               'revisionday',
+               'revisionday2',
+               'revisionmonth',
+               'revisionmonth1',
+               'revisionyear',
+               'revisiontimestamp',
+               'revisionuser',
+               'revisionsize',
+               'subpagename',
+               'subpagenamee',
+               'talkspace',
+               'talkspacee',
+               'subjectspace',
+               'subjectspacee',
+               'talkpagename',
+               'talkpagenamee',
+               'subjectpagename',
+               'subjectpagenamee',
+               'numberofusers',
+               'numberofactiveusers',
+               'numberofpages',
+               'currentversion',
+               'rootpagename',
+               'rootpagenamee',
+               'basepagename',
+               'basepagenamee',
+               'currenttimestamp',
+               'localtimestamp',
+               'directionmark',
+               'contentlanguage',
+               'pagelanguage',
+               'numberofadmins',
+               'cascadingsources',
+       ];
+
+       /** Array of caching hints for ParserCache
+        * @var array [ string => int ]
+        */
+       private $mCacheTTLs = [
+               'currentmonth' => 86400,
+               'currentmonth1' => 86400,
+               'currentmonthname' => 86400,
+               'currentmonthnamegen' => 86400,
+               'currentmonthabbrev' => 86400,
+               'currentday' => 3600,
+               'currentday2' => 3600,
+               'currentdayname' => 3600,
+               'currentyear' => 86400,
+               'currenttime' => 3600,
+               'currenthour' => 3600,
+               'localmonth' => 86400,
+               'localmonth1' => 86400,
+               'localmonthname' => 86400,
+               'localmonthnamegen' => 86400,
+               'localmonthabbrev' => 86400,
+               'localday' => 3600,
+               'localday2' => 3600,
+               'localdayname' => 3600,
+               'localyear' => 86400,
+               'localtime' => 3600,
+               'localhour' => 3600,
+               'numberofarticles' => 3600,
+               'numberoffiles' => 3600,
+               'numberofedits' => 3600,
+               'currentweek' => 3600,
+               'currentdow' => 3600,
+               'localweek' => 3600,
+               'localdow' => 3600,
+               'numberofusers' => 3600,
+               'numberofactiveusers' => 3600,
+               'numberofpages' => 3600,
+               'currentversion' => 86400,
+               'currenttimestamp' => 3600,
+               'localtimestamp' => 3600,
+               'pagesinnamespace' => 3600,
+               'numberofadmins' => 3600,
+               'numberingroup' => 3600,
+       ];
+
+       /** @var string[] */
+       private $mDoubleUnderscoreIDs = [
+               'notoc',
+               'nogallery',
+               'forcetoc',
+               'toc',
+               'noeditsection',
+               'newsectionlink',
+               'nonewsectionlink',
+               'hiddencat',
+               'index',
+               'noindex',
+               'staticredirect',
+               'notitleconvert',
+               'nocontentconvert',
+       ];
+
+       /** @var string[] */
+       private $mSubstIDs = [
+               'subst',
+               'safesubst',
+       ];
+
+       /** @var array [ string => MagicWord ] */
+       private $mObjects = [];
+
+       /** @var MagicWordArray */
+       private $mDoubleUnderscoreArray = null;
+
+       /**#@-*/
+
+       /**
+        * Factory: creates an object representing an ID
+        *
+        * @param string $id The internal name of the magic word
+        *
+        * @return MagicWord
+        */
+       public function get( $id ) {
+               if ( !isset( $this->mObjects[$id] ) ) {
+                       $mw = new MagicWord();
+                       $mw->load( $id );
+                       $this->mObjects[$id] = $mw;
+               }
+               return $this->mObjects[$id];
+       }
+
+       /**
+        * Get an array of parser variable IDs
+        *
+        * @return string[]
+        */
+       public function getVariableIDs() {
+               if ( !$this->mVariableIDsInitialised ) {
+                       # Get variable IDs
+                       Hooks::run( 'MagicWordwgVariableIDs', [ &$this->mVariableIDs ] );
+                       $this->mVariableIDsInitialised = true;
+               }
+               return $this->mVariableIDs;
+       }
+
+       /**
+        * Get an array of parser substitution modifier IDs
+        * @return string[]
+        */
+       public function getSubstIDs() {
+               return $this->mSubstIDs;
+       }
+
+       /**
+        * Allow external reads of TTL array
+        *
+        * @param string $id
+        * @return int
+        */
+       public function getCacheTTL( $id ) {
+               if ( array_key_exists( $id, $this->mCacheTTLs ) ) {
+                       return $this->mCacheTTLs[$id];
+               } else {
+                       return -1;
+               }
+       }
+
+       /**
+        * Get a MagicWordArray of double-underscore entities
+        *
+        * @return MagicWordArray
+        */
+       public function getDoubleUnderscoreArray() {
+               if ( is_null( $this->mDoubleUnderscoreArray ) ) {
+                       Hooks::run( 'GetDoubleUnderscoreIDs', [ &$this->mDoubleUnderscoreIDs ] );
+                       $this->mDoubleUnderscoreArray = new MagicWordArray( $this->mDoubleUnderscoreIDs );
+               }
+               return $this->mDoubleUnderscoreArray;
+       }
+}
index fba15c1..f891042 100644 (file)
@@ -51,6 +51,7 @@ use TitleFormatter;
 use TitleParser;
 use VirtualRESTServiceClient;
 use MediaWiki\Interwiki\InterwikiLookup;
+use MagicWordFactory;
 
 /**
  * Service locator for MediaWiki core services.
@@ -864,6 +865,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'ConfigRepository' );
        }
 
+       /**
+        * @since 1.32
+        * @return MagicWordFactory
+        */
+       public function getMagicWordFactory() {
+               return $this->getService( 'MagicWordFactory' );
+       }
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service getter here, don't forget to add a test
        // case for it in MediaWikiServicesTest::provideGetters() and in
index 7d49080..0c63d4c 100644 (file)
@@ -600,6 +600,11 @@ return [
                );
        },
 
+       'MagicWordFactory' => function ( MediaWikiServices $services ) {
+               global $wgContLang;
+               return new MagicWordFactory( $wgContLang );
+       },
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service here, don't forget to add a getter function
        // in the MediaWikiServices class. The convenience getter should just call
index 5eb91c3..26e4e9f 100644 (file)
@@ -1152,7 +1152,7 @@ class ParserTestRunner {
                $lang->resetNamespaces();
                $setup['wgContLang'] = $lang;
                $reset = function () {
-                       MagicWord::clearCache();
+                       MediaWikiServices::getInstance()->resetServiceForTesting( 'MagicWordFactory' );
                        $this->resetTitleServices();
                };
                $setup[] = $reset;
index 164c83c..94de088 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Parser-related tests that don't suit for parserTests.txt
  *
@@ -28,7 +30,7 @@ class ExtraParserTest extends MediaWikiTestCase {
                $this->options->setTemplateCallback( [ __CLASS__, 'statelessFetchTemplate' ] );
                $this->parser = new Parser;
 
-               MagicWord::clearCache();
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'MagicWordFactory' );
        }
 
        /**
index 7763aff..4189e93 100644 (file)
@@ -365,6 +365,7 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        'PreferencesFactory' => [ 'PreferencesFactory', PreferencesFactory::class ],
                        'ActorMigration' => [ 'ActorMigration', ActorMigration::class ],
                        'ConfigRepository' => [ 'ConfigRepository', \MediaWiki\Config\ConfigRepository::class ],
+                       'MagicWordFactory' => [ 'MagicWordFactory', MagicWordFactory::class ],
                ];
        }
 
index 59984d8..4bb1ed2 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * @group ContentHandler
  */
@@ -81,7 +83,7 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
                global $wgContLang;
                $wgContLang->resetNamespaces();
 
-               MagicWord::clearCache();
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'MagicWordFactory' );
 
                if ( is_string( $title ) ) {
                        $title = Title::newFromText( $title );