Merge "Removed old "noPush" config hacks from FileBackendMultiWrite"
[lhc/web/wiklou.git] / includes / libs / ObjectFactory.php
index ee696c3..1cb544b 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 /**
- * @section LICENSE
  * 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
@@ -47,26 +46,31 @@ class ObjectFactory {
         * expanded by invoking them with no arguments before passing the
         * resulting value on to the constructor/callable. This can be used to
         * pass DatabaseBase instances or other live objects to the
-        * constructor/callable.
+        * 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
         * contain 'class' or 'factory' keys
         * @throws ReflectionException when 'args' are supplied and 'class'
-        * constructor is non-public or non-existant
+        * constructor is non-public or non-existent
         */
        public static function getObjectFromSpec( $spec ) {
                $args = isset( $spec['args'] ) ? $spec['args'] : array();
+               $expandArgs = !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'] ) ) {
                        $clazz = $spec['class'];
@@ -84,6 +88,33 @@ class ObjectFactory {
                        );
                }
 
+               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 );
+       }
 }