BryanDavis has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/228020

Change subject: ObjectFactory: add support for setter injection
......................................................................

ObjectFactory: add support for setter injection

Extend ObjectFactory::getObjectFromSpec() to support setter injection on
created objects when the specification includes a 'calls' member.

Bug: T107440
Change-Id: Ie2ece2e9658dd2d895d3935da4dc2da8a0a316e2
---
M includes/libs/ObjectFactory.php
M tests/phpunit/includes/libs/ObjectFactoryTest.php
2 files changed, 63 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/20/228020/1

diff --git a/includes/libs/ObjectFactory.php b/includes/libs/ObjectFactory.php
index ec8c36a..1cb544b 100644
--- a/includes/libs/ObjectFactory.php
+++ b/includes/libs/ObjectFactory.php
@@ -49,6 +49,13 @@
         * constructor/callable. This behavior can be suppressed by adding
         * closure_expansion => false to the specification.
         *
+        * The specification may also contain a 'calls' key that describes 
method
+        * calls to make on the newly created object before returning it. This
+        * pattern is often known as "setter injection". The value of this key 
is
+        * expected to be an associative array with method names as keys and
+        * argument lists as values. The argument list will be expanded (or not)
+        * in the same way as the 'args' key for the main object.
+        *
         * @param array $spec Object specification
         * @return object
         * @throws InvalidArgumentException when object specification does not
@@ -58,18 +65,11 @@
         */
        public static function getObjectFromSpec( $spec ) {
                $args = isset( $spec['args'] ) ? $spec['args'] : array();
+               $expandArgs = !isset( $spec['closure_expansion'] ) ||
+                       $spec['closure_expansion'] === true;
 
-               if ( !isset( $spec['closure_expansion'] ) ||
-                       $spec['closure_expansion'] === true
-               ) {
-                       $args = array_map( function ( $value ) {
-                               if ( is_object( $value ) && $value instanceof 
Closure ) {
-                                       // If an argument is a Closure, call it.
-                                       return $value();
-                               } else {
-                                       return $value;
-                               }
-                       }, $args );
+               if ( $expandArgs ) {
+                       $args = static::expandClosures( $args );
                }
 
                if ( isset( $spec['class'] ) ) {
@@ -88,6 +88,33 @@
                        );
                }
 
+               if ( isset( $spec['calls'] ) && is_array( $spec['calls'] ) ) {
+                       // Call additional methods on the newly created object
+                       foreach ( $spec['calls'] as $method => $margs ) {
+                               if ( $expandArgs ) {
+                                       $margs = static::expandClosures( $margs 
);
+                               }
+                               call_user_func_array( array( $obj, $method ), 
$margs );
+                       }
+               }
+
                return $obj;
        }
+
+       /**
+        * Iterate a list and call any closures it contains.
+        *
+        * @param array $list List of things
+        * @return array List with any Closures replaced with their output
+        */
+       protected static function expandClosures( $list ) {
+               return array_map( function ( $value ) {
+                       if ( is_object( $value ) && $value instanceof Closure ) 
{
+                               // If $value is a Closure, call it.
+                               return $value();
+                       } else {
+                               return $value;
+                       }
+               }, $list );
+       }
 }
diff --git a/tests/phpunit/includes/libs/ObjectFactoryTest.php 
b/tests/phpunit/includes/libs/ObjectFactoryTest.php
index a9d3cc1..aea037e 100644
--- a/tests/phpunit/includes/libs/ObjectFactoryTest.php
+++ b/tests/phpunit/includes/libs/ObjectFactoryTest.php
@@ -29,10 +29,17 @@
                        'args' => array( function() {
                                return 'unwrapped';
                        }, ),
+                       'calls' => array(
+                               'setter' => array( function() {
+                                       return 'unwrapped';
+                               }, ),
+                       ),
                        'closure_expansion' => false,
                ) );
                $this->assertInstanceOf( 'Closure', $obj->args[0] );
                $this->assertSame( 'unwrapped', $obj->args[0]() );
+               $this->assertInstanceOf( 'Closure', $obj->setterArgs[0] );
+               $this->assertSame( 'unwrapped', $obj->setterArgs[0]() );
        }
 
        /**
@@ -44,25 +51,43 @@
                        'args' => array( function() {
                                return 'unwrapped';
                        }, ),
+                       'calls' => array(
+                               'setter' => array( function() {
+                                       return 'unwrapped';
+                               }, ),
+                       ),
                        'closure_expansion' => true,
                ) );
                $this->assertInternalType( 'string', $obj->args[0] );
                $this->assertSame( 'unwrapped', $obj->args[0] );
+               $this->assertInternalType( 'string', $obj->setterArgs[0] );
+               $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
 
                $obj = ObjectFactory::getObjectFromSpec( array(
                        'class' => 'ObjectFactoryTest_Fixture',
                        'args' => array( function() {
                                return 'unwrapped';
                        }, ),
+                       'calls' => array(
+                               'setter' => array( function() {
+                                       return 'unwrapped';
+                               }, ),
+                       ),
                ) );
                $this->assertInternalType( 'string', $obj->args[0] );
                $this->assertSame( 'unwrapped', $obj->args[0] );
+               $this->assertInternalType( 'string', $obj->setterArgs[0] );
+               $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
        }
 }
 
 class ObjectFactoryTest_Fixture {
        public $args;
+       public $setterArgs;
        public function __construct( /*...*/ ) {
                $this->args = func_get_args();
        }
+       public function setter( /*...*/ ) {
+               $this->setterArgs = func_get_args();
+       }
 }

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie2ece2e9658dd2d895d3935da4dc2da8a0a316e2
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: BryanDavis <[email protected]>

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

Reply via email to