Support the creation of special pages with services injected
authormainframe98 <k.s.werf@hotmail.com>
Fri, 6 Sep 2019 09:21:29 +0000 (11:21 +0200)
committermainframe98 <k.s.werf@hotmail.com>
Sun, 8 Sep 2019 10:57:54 +0000 (12:57 +0200)
Now that the ObjectFactory library supports object creation with
services (T222409), the special page factory can use the object
factory to create special pages based off a spec, allowing the
creation of special pages that need services injected.

The object factory now also handles constructing from class name
and from callable.

This also deprecates providing the special page list with an
instance of SpecialPage, which hasn't been necessary since
r15031.

Bug: T222388
Change-Id: Iabb78ce5c98cfb3b586644be35d984871cb750cb

RELEASE-NOTES-1.34
docs/extension.schema.v1.json
docs/extension.schema.v2.json
includes/ServiceWiring.php
includes/specialpage/SpecialPageFactory.php
tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php

index aaf4d78..eaabd2f 100644 (file)
@@ -117,6 +117,9 @@ $wgPasswordPolicy['policies']['default']['PasswordNotInLargeBlacklist'] = false;
   GetBlockedStatus.
 * ObjectFactory is available as a service. When used as a service, the object
   specs can now specify needed DI services.
   GetBlockedStatus.
 * ObjectFactory is available as a service. When used as a service, the object
   specs can now specify needed DI services.
+* (T222388) Special pages can now be specified as an ObjectFactory spec,
+  allowing the construction of special pages that require services to be
+  injected in their constructor.
 
 === External library changes in 1.34 ===
 
 
 === External library changes in 1.34 ===
 
@@ -492,6 +495,9 @@ because of Phabricator reports.
   or extend RevisionSearchResult.
 * Skin::getSkinNameMessages() is deprecated and no longer used.
 * The mediawiki.RegExp module is deprecated; use mw.util.escapeRegExp() instead.
   or extend RevisionSearchResult.
 * Skin::getSkinNameMessages() is deprecated and no longer used.
 * The mediawiki.RegExp module is deprecated; use mw.util.escapeRegExp() instead.
+* Specifying a SpecialPage object for the list of special pages (either through
+  the SpecialPage_initList hook or by adding to $wgSpecialPages) is now
+  deprecated.
 
 === Other changes in 1.34 ===
 * …
 
 === Other changes in 1.34 ===
 * …
index 9ce016f..06701cd 100644 (file)
                },
                "SpecialPages": {
                        "type": "object",
                },
                "SpecialPages": {
                        "type": "object",
-                       "description": "SpecialPages implemented in this extension (mapping of page name to class name)"
+                       "description": "SpecialPages implemented in this extension (mapping of page name to class name or to ObjectFactory spec)"
                },
                "AutoloadNamespaces": {
                        "type": "object",
                },
                "AutoloadNamespaces": {
                        "type": "object",
index 9d874f4..56d274b 100644 (file)
                },
                "SpecialPages": {
                        "type": "object",
                },
                "SpecialPages": {
                        "type": "object",
-                       "description": "SpecialPages implemented in this extension (mapping of page name to class name)"
+                       "description": "SpecialPages implemented in this extension (mapping of page name to class name or to ObjectFactory spec)"
                },
                "AutoloadNamespaces": {
                        "type": "object",
                },
                "AutoloadNamespaces": {
                        "type": "object",
index 740377c..f42ef31 100644 (file)
@@ -734,7 +734,8 @@ return [
                return new SpecialPageFactory(
                        new ServiceOptions(
                                SpecialPageFactory::$constructorOptions, $services->getMainConfig() ),
                return new SpecialPageFactory(
                        new ServiceOptions(
                                SpecialPageFactory::$constructorOptions, $services->getMainConfig() ),
-                       $services->getContentLanguage()
+                       $services->getContentLanguage(),
+                       $services->getObjectFactory()
                );
        },
 
                );
        },
 
index 8134c9a..2737e35 100644 (file)
@@ -34,6 +34,7 @@ use RequestContext;
 use SpecialPage;
 use Title;
 use User;
 use SpecialPage;
 use Title;
 use User;
+use Wikimedia\ObjectFactory;
 
 /**
  * Factory for handling the special page list and generating SpecialPage objects.
 
 /**
  * Factory for handling the special page list and generating SpecialPage objects.
@@ -221,6 +222,9 @@ class SpecialPageFactory {
        /** @var Language */
        private $contLang;
 
        /** @var Language */
        private $contLang;
 
+       /** @var ObjectFactory */
+       private $objectFactory;
+
        /**
         * TODO Make this a const when HHVM support is dropped (T192166)
         *
        /**
         * TODO Make this a const when HHVM support is dropped (T192166)
         *
@@ -241,11 +245,17 @@ class SpecialPageFactory {
        /**
         * @param ServiceOptions $options
         * @param Language $contLang
        /**
         * @param ServiceOptions $options
         * @param Language $contLang
+        * @param ObjectFactory $objectFactory
         */
         */
-       public function __construct( ServiceOptions $options, Language $contLang ) {
+       public function __construct(
+               ServiceOptions $options,
+               Language $contLang,
+               ObjectFactory $objectFactory
+       ) {
                $options->assertRequiredOptions( self::$constructorOptions );
                $this->options = $options;
                $this->contLang = $contLang;
                $options->assertRequiredOptions( self::$constructorOptions );
                $this->options = $options;
                $this->contLang = $contLang;
+               $this->objectFactory = $objectFactory;
        }
 
        /**
        }
 
        /**
@@ -412,14 +422,22 @@ class SpecialPageFactory {
                if ( isset( $specialPageList[$realName] ) ) {
                        $rec = $specialPageList[$realName];
 
                if ( isset( $specialPageList[$realName] ) ) {
                        $rec = $specialPageList[$realName];
 
-                       if ( is_callable( $rec ) ) {
-                               // Use callback to instantiate the special page
-                               $page = $rec();
-                       } elseif ( is_string( $rec ) ) {
-                               $className = $rec;
-                               $page = new $className;
-                       } elseif ( $rec instanceof SpecialPage ) {
+                       if ( $rec instanceof SpecialPage ) {
+                               wfDeprecated(
+                                       "a SpecialPage instance (for $realName) in " .
+                                       '$wgSpecialPages or from the SpecialPage_initList hook',
+                                       '1.34'
+                               );
+
                                $page = $rec; // XXX: we should deep clone here
                                $page = $rec; // XXX: we should deep clone here
+                       } elseif ( is_array( $rec ) || is_string( $rec ) || is_callable( $rec ) ) {
+                               $page = $this->objectFactory->createObject(
+                                       $rec,
+                                       [
+                                               'allowClassName' => true,
+                                               'allowCallable' => true
+                                       ]
+                               );
                        } else {
                                $page = null;
                        }
                        } else {
                                $page = null;
                        }
index c0376ad..a5d5946 100644 (file)
@@ -60,6 +60,10 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
                        'callback array' => [
                                [ 'SpecialPageTestHelper', 'newSpecialAllPages' ],
                                false
                        'callback array' => [
                                [ 'SpecialPageTestHelper', 'newSpecialAllPages' ],
                                false
+                       ],
+                       'object factory spec' => [
+                               [ 'class' => SpecialAllPages::class ],
+                               false
                        ]
                ];
        }
                        ]
                ];
        }
@@ -264,4 +268,29 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
                $this->assertTrue( $called, 'Recursive call succeeded' );
        }
 
                $this->assertTrue( $called, 'Recursive call succeeded' );
        }
 
+       /**
+        * @covers \MediaWiki\Special\SpecialPageFactory::getPage
+        */
+       public function testSpecialPageCreationThatRequiresService() {
+               $type = null;
+
+               $this->setMwGlobals( 'wgSpecialPages',
+                       [ 'TestPage' => [
+                               'factory' => function ( $spf ) use ( &$type ) {
+                                       $type = get_class( $spf );
+
+                                       return new class() extends SpecialPage {
+
+                                       };
+                               },
+                               'services' => [
+                                       'SpecialPageFactory'
+                               ]
+                       ] ]
+               );
+
+               SpecialPageFactory::getPage( 'TestPage' );
+
+               $this->assertEquals( \MediaWiki\Special\SpecialPageFactory::class, $type );
+       }
 }
 }