Add ObjectFactory as a service
authorBrad Jorsch <bjorsch@wikimedia.org>
Wed, 21 Aug 2019 16:10:30 +0000 (12:10 -0400)
committerDaniel Kinzler <dkinzler@wikimedia.org>
Fri, 23 Aug 2019 08:46:48 +0000 (08:46 +0000)
ObjectFactory exists to handle lazy instantiation of objects based on
declarative specifications.

One drawback to the current use of static ObjectFactory::getObjectFromSpec()
is that it doesn't have a good way to handle dependency injection. The
best you could do is refer to a static 'factory' function in your
specification, and that function would access the global service
container. But DI would prefer not to have that "global service
container" being accessed.

The solution is to have a non-static ObjectFactory that can supply
the needed services based on the object definition. For example,

 [
     'class' => MyObject::class,
     'services' => [ 'FooFactory', 'BarFactory' ],
 ]

would get the FooFactory and BarFactory from a service container to pass
into MyObject's constructor.

But in order for that to be possible, you need to have an instance of
ObjectFactory that has reference to the service container from which to
fetch the services. And the most DI-correct way to get that is to have
it dependency-injected into your constructor, at which point the
ObjectFactory instance should itself be a service in the DI service
container.

Bug: T222409
Change-Id: I2a56059a9209abce0b22fb93c9f9c6a09a825c56

RELEASE-NOTES-1.34
includes/MediaWikiServices.php
includes/ServiceWiring.php

index 3f4287b..d60b35e 100644 (file)
@@ -100,6 +100,8 @@ For notes on 1.33.x and older releases, see HISTORY.
   See <https://www.mediawiki.org/wiki/OOUI/Themes> for details.
 * (T229035) The GetUserBlock hook was added. Use this instead of
   GetBlockedStatus.
+* ObjectFactory is available as a service. When used as a service, the object
+  specs can now specify needed DI services.
 
 === External library changes in 1.34 ===
 
index 8445842..1ffbf1d 100644 (file)
@@ -65,6 +65,7 @@ use SkinFactory;
 use TitleFormatter;
 use TitleParser;
 use VirtualRESTServiceClient;
+use Wikimedia\ObjectFactory;
 use Wikimedia\Rdbms\LBFactory;
 use Wikimedia\Services\SalvageableService;
 use Wikimedia\Services\ServiceContainer;
@@ -749,6 +750,17 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'NameTableStoreFactory' );
        }
 
+       /**
+        * ObjectFactory is intended for instantiating "handlers" from declarative definitions,
+        * such as Action API modules, special pages, or REST API handlers.
+        *
+        * @since 1.34
+        * @return ObjectFactory
+        */
+       public function getObjectFactory() {
+               return $this->getService( 'ObjectFactory' );
+       }
+
        /**
         * @since 1.32
         * @return OldRevisionImporter
index 7bdd7c8..f9d5ca1 100644 (file)
@@ -70,6 +70,7 @@ use MediaWiki\Storage\BlobStoreFactory;
 use MediaWiki\Storage\NameTableStoreFactory;
 use MediaWiki\Storage\SqlBlobStore;
 use MediaWiki\Storage\PageEditStash;
+use Wikimedia\ObjectFactory;
 
 return [
        'ActorMigration' => function ( MediaWikiServices $services ) : ActorMigration {
@@ -480,6 +481,10 @@ return [
                );
        },
 
+       'ObjectFactory' => function ( MediaWikiServices $services ) : ObjectFactory {
+               return new ObjectFactory( $services );
+       },
+
        'OldRevisionImporter' => function ( MediaWikiServices $services ) : OldRevisionImporter {
                return new ImportableOldRevisionImporter(
                        true,