Next take on setter injection - an alternate implementation binder, which is also...
authorChuck Hagenbuch <chuck@horde.org>
Wed, 28 Apr 2010 03:52:56 +0000 (23:52 -0400)
committerChuck Hagenbuch <chuck@horde.org>
Wed, 28 Apr 2010 03:52:56 +0000 (23:52 -0400)
framework/Injector/lib/Horde/Injector.php
framework/Injector/lib/Horde/Injector/Binder/Implementation.php
framework/Injector/lib/Horde/Injector/Binder/ImplementationWithSetters.php [new file with mode: 0644]
framework/Injector/lib/Horde/Injector/TopLevel.php
framework/Injector/package.xml

index e2d3771..eefb3ef 100644 (file)
@@ -234,34 +234,4 @@ class Horde_Injector implements Horde_Injector_Scope
 
         return $this->_instances[$interface];
     }
-
-    /**
-     */
-    public function getMethodDependencies(ReflectionMethod $method)
-    {
-        $dependencies = array();
-
-        try {
-            foreach ($method->getParameters() as $parameter) {
-                $dependencies[] = $this->_getParameterDependency($parameter);
-            }
-        } catch (Exception $e) {
-            throw new Horde_Injector_Exception("$method has unfulfilled dependencies ($parameter)", 0, $e);
-        }
-
-        return $dependencies;
-    }
-
-    /**
-     */
-    private function _getParameterDependency(ReflectionParameter $parameter)
-    {
-        if ($parameter->getClass()) {
-            return $this->getInstance($parameter->getClass()->getName());
-        } elseif ($parameter->isOptional()) {
-            return $parameter->getDefaultValue();
-        }
-
-        throw new Horde_Injector_Exception("Untyped parameter \$" . $parameter->getName() . "can't be fulfilled");
-    }
 }
index a5c9e59..f188e38 100644 (file)
@@ -12,12 +12,12 @@ class Horde_Injector_Binder_Implementation implements Horde_Injector_Binder
     /**
      * TODO
      */
-    private $_implementation;
+    protected $_implementation;
 
     /**
      * TODO
      */
-    private $_setters;
+    protected $_setters;
 
     /**
      * TODO
@@ -69,7 +69,7 @@ class Horde_Injector_Binder_Implementation implements Horde_Injector_Binder
     /**
      * TODO
      */
-    private function _validateImplementation(ReflectionClass $reflectionClass)
+    protected function _validateImplementation(ReflectionClass $reflectionClass)
     {
         if ($reflectionClass->isAbstract() || $reflectionClass->isInterface()) {
             throw new Horde_Injector_Exception('Cannot bind interfaces or abstract classes "' . $this->_implementation . '" to an interface.');
@@ -79,24 +79,54 @@ class Horde_Injector_Binder_Implementation implements Horde_Injector_Binder
     /**
      * TODO
      */
-    private function _getInstance(Horde_Injector $injector, ReflectionClass $class)
+    protected function _getInstance(Horde_Injector $injector, ReflectionClass $class)
     {
         return $class->getConstructor()
-            ? $class->newInstanceArgs($injector->getMethodDependencies($class->getConstructor()))
+            ? $class->newInstanceArgs($this->_getMethodDependencies($injector, $class->getConstructor()))
             : $class->newInstance();
     }
 
     /**
      * TODO
      */
-    private function _callSetters(Horde_Injector $injector, $instance)
+    protected function _callSetters(Horde_Injector $injector, $instance)
     {
         foreach ($this->_setters as $setter) {
             $reflectionMethod = new ReflectionMethod($instance, $setter);
             $reflectionMethod->invokeArgs(
                 $instance,
-                $injector->getMethodDependencies($reflectionMethod)
+                $this->_getMethodDependencies($injector, $reflectionMethod)
             );
         }
     }
+
+    /**
+     */
+    protected function _getMethodDependencies(Horde_Injector $injector, ReflectionMethod $method)
+    {
+        $dependencies = array();
+
+        try {
+            foreach ($method->getParameters() as $parameter) {
+                $dependencies[] = $this->_getParameterDependency($injector, $parameter);
+            }
+        } catch (Horde_Injector_Exception $e) {
+            throw new Horde_Injector_Exception("$method has unfulfilled dependencies ($parameter)", 0, $e);
+        }
+
+        return $dependencies;
+    }
+
+    /**
+     */
+    protected function _getParameterDependency(Horde_Injector $injector, ReflectionParameter $parameter)
+    {
+        if ($parameter->getClass()) {
+            return $injector->getInstance($parameter->getClass()->getName());
+        } elseif ($parameter->isOptional()) {
+            return $parameter->getDefaultValue();
+        }
+
+        throw new Horde_Injector_Exception("Untyped parameter \$" . $parameter->getName() . "can't be fulfilled");
+    }
 }
diff --git a/framework/Injector/lib/Horde/Injector/Binder/ImplementationWithSetters.php b/framework/Injector/lib/Horde/Injector/Binder/ImplementationWithSetters.php
new file mode 100644 (file)
index 0000000..2053bd9
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * TODO
+ *
+ * @author   Bob Mckee <bmckee@bywires.com>
+ * @author   James Pepin <james@jamespepin.com>
+ * @category Horde
+ * @package  Horde_Injector
+ */
+class Horde_Injector_Binder_ImplementationWithSetters extends Horde_Injector_Binder_Implementation
+{
+    /**
+     * TODO
+     */
+    public function create(Horde_Injector $injector)
+    {
+        $reflectionClass = new ReflectionClass($this->_implementation);
+        $this->_validateImplementation($reflectionClass);
+        $instance = $this->_getInstance($injector, $reflectionClass);
+        $setters = $this->_findSetters($reflectionClass);
+        foreach ($setters as $setter) {
+            $this->bindSetter($setter);
+        }
+        $this->_callSetters($injector, $instance);
+        return $instance;
+    }
+
+    /**
+     * Find all public methods in $reflectionClass that are annotated with
+     * @inject.
+     *
+     * @param ReflectionClass $reflectionClass
+     *
+     * @return array
+     */
+    private function _findSetters(ReflectionClass $reflectionClass)
+    {
+        $setters = array();
+        foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
+            $docBlock = $reflectionMethod->getDocComment();
+            if ($docBlock) {
+                if (strpos($docBlock, '@inject') !== false) {
+                    $setters[] = $reflectionMethod->name;
+                }
+            }
+        }
+
+        return $setters;
+    }
+}
index 76d5650..130d3f8 100644 (file)
@@ -18,11 +18,11 @@ class Horde_Injector_TopLevel implements Horde_Injector_Scope
      * Get an Implementation Binder that maps the $interface to itself
      *
      * @param string $interface The interface to retrieve binding information for
-     * @return Horde_Injector_Binder_Implementation a new binding object that maps the interface to itself
+     * @return Horde_Injector_Binder_ImplementationWithSetters a new binding object that maps the interface to itself, with setter injection
      */
     public function getBinder($interface)
     {
-        return new Horde_Injector_Binder_Implementation($interface, $interface);
+        return new Horde_Injector_Binder_ImplementationWithSetters($interface, $interface);
     }
 
     /**
index 7b77ebc..93651eb 100644 (file)
@@ -62,6 +62,7 @@
        <file name="Closure.php" role="php" />
        <file name="Factory.php" role="php" />
        <file name="Implementation.php" role="php" />
+       <file name="ImplementationWithSetters.php" role="php" />
       </dir> <!-- /lib/Horde/Injector/Binder -->
       <file name="Binder.php" role="php" />
       <file name="Exception.php" role="php" />
    <install as="Horde/Injector/Binder/Closure.php" name="lib/Horde/Injector/Binder/Closure.php" />
    <install as="Horde/Injector/Binder/Factory.php" name="lib/Horde/Injector/Binder/Factory.php" />
    <install as="Horde/Injector/Binder/Implementation.php" name="lib/Horde/Injector/Binder/Implementation.php" />
+   <install as="Horde/Injector/Binder/ImplementationWithSetters.php" name="lib/Horde/Injector/Binder/ImplementationWithSetters.php" />
    <install as="Horde/Injector/AllTests.php" name="test/Horde/Injector/AllTests.php" />
    <install as="Horde/Injector/BinderTest.php" name="test/Horde/Injector/BinderTest.php" />
    <install as="Horde/Injector/InjectorTest.php" name="test/Horde/Injector/InjectorTest.php" />