{
private $_parentInjector;
private $_bindings = array();
+ private $_filters = array();
private $_instances;
/**
*/
public function createInstance($interface)
{
- return $this->getBinder($interface)->create($this);
+ $instance = $this->getBinder($interface)->create($this);
+ $this->runFilters($instance);
+ return $instance;
}
/**
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");
+ }
+
+ /**
+ * Add an object creation filter
+ */
+ public function addFilter(Horde_Injector_Filter $filter)
+ {
+ $this->_filters[] = $filter;
+ }
+
+ /**
+ * Run object creation filters on a new object
+ *
+ * @param object $instance The new instance to filter.
+ */
+ public function runFilters($instance)
+ {
+ foreach ($this->_filters as $filter) {
+ $filter->filter($this, $instance);
+ }
+ }
}
/**
* TODO
*/
- private function _getInstance(Horde_Injector $injector,
- ReflectionClass $class)
+ private function _getInstance(Horde_Injector $injector, ReflectionClass $class)
{
return $class->getConstructor()
- ? $class->newInstanceArgs($this->_getMethodDependencies($injector, $class->getConstructor()))
+ ? $class->newInstanceArgs($injector->getMethodDependencies($class->getConstructor()))
: $class->newInstance();
}
/**
* TODO
*/
- private function _getMethodDependencies(Horde_Injector $injector,
- ReflectionMethod $method)
- {
- $dependencies = array();
-
- foreach ($method->getParameters() as $parameter) {
- $dependencies[] = $this->_getParameterDependency($injector, $parameter);
- }
-
- return $dependencies;
- }
-
- /**
- * TODO
- */
- private 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('Unable to instantiate class "' . $this->_implementation . '" because a value could not be determined untyped parameter "$' . $parameter->getName() . '"');
- }
-
- /**
- * TODO
- */
private function _callSetters(Horde_Injector $injector, $instance)
{
foreach ($this->_setters as $setter) {
$reflectionMethod = new ReflectionMethod($instance, $setter);
$reflectionMethod->invokeArgs(
$instance,
- $this->_getMethodDependencies($injector, $reflectionMethod)
+ $injector->getMethodDependencies($reflectionMethod)
);
}
}
-
}
--- /dev/null
+<?php
+/**
+ * Interface for object post-creation filters.
+ *
+ * @author Bob Mckee <bmckee@bywires.com>
+ * @author James Pepin <james@jamespepin.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package Horde_Injector
+ */
+interface Horde_Injector_Filter
+{
+ /**
+ * @param Horde_Injector $injector The active Horde_Injector
+ * @param object $instance The new instance to filter
+ *
+ * @return void
+ */
+ public function filter(Horde_Injector $injector, $instance);
+}
--- /dev/null
+<?php
+/**
+ * Filter that finds variables marked with @inject and injects them into an
+ * object.
+ *
+ * @author Bob Mckee <bmckee@bywires.com>
+ * @author James Pepin <james@jamespepin.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package Horde_Injector
+ */
+class Horde_Injector_Filter_AnnotatedSetterInjector implements Horde_Injector_Filter
+{
+ /**
+ * @var Horde_Injector_DependencyFinder
+ */
+ protected $_dependencyFinder;
+
+ /**
+ * Inspect the object's class docblock for @inject annotations, and fill
+ * those objects in through their setter methods.
+ *
+ * @param object $instance The object to do setter injection on.
+ */
+ public function filter(Horde_Injector $injector, $instance)
+ {
+ $reflectionClass = new ReflectionClass($instance);
+ $setters = $this->_findSetters($reflectionClass);
+ $this->_callSetters($injector, $instance, $setters);
+ }
+
+ /**
+ * Find annotated setters in the class docblock
+ *
+ * @param ReflectionClass $reflectionClass
+ *
+ * @return array
+ */
+ private function _findSetters(ReflectionClass $reflectionClass)
+ {
+ $setters = array();
+ $docBlock = $reflectionClass->getDocComment();
+ if ($docBlock) {
+ if (preg_match_all('/@inject (\w+)/', $docBlock, $matches)) {
+ foreach ($matches[1] as $setter) {
+ $setters[] = $setter;
+ }
+ }
+ }
+
+ return $setters;
+ }
+
+ /**
+ * TODO
+ */
+ private function _callSetters(Horde_Injector $injector, $instance, $setters)
+ {
+ foreach ($setters as $setter) {
+ $reflectionMethod = new ReflectionMethod($instance, $setter);
+ $reflectionMethod->invokeArgs(
+ $instance,
+ $injector->getMethodDependencies($reflectionMethod)
+ );
+ }
+ }
+}
<file name="Factory.php" role="php" />
<file name="Implementation.php" role="php" />
</dir> <!-- /lib/Horde/Injector/Binder -->
+ <dir name="Filter">
+ <file name="AnnotatedSetterInjector.php" role="php" />
+ </dir> <!-- /lib/Horde/Injector/Filter -->
<file name="Binder.php" role="php" />
<file name="Exception.php" role="php" />
+ <file name="Filter.php" role="php" />
<file name="Scope.php" role="php" />
<file name="TopLevel.php" role="php" />
</dir> <!-- /lib/Horde/Injector -->
<install as="Horde/Injector.php" name="lib/Horde/Injector.php" />
<install as="Horde/Injector/Binder.php" name="lib/Horde/Injector/Binder.php" />
<install as="Horde/Injector/Exception.php" name="lib/Horde/Injector/Exception.php" />
+ <install as="Horde/Injector/Filter.php" name="lib/Horde/Injector/Filter.php" />
<install as="Horde/Injector/Scope.php" name="lib/Horde/Injector/Scope.php" />
<install as="Horde/Injector/TopLevel.php" name="lib/Horde/Injector/TopLevel.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/Filter/AnnotatedSetterInjector.php" name="lib/Horde/Injector/Filter/AnnotatedSetterInjector.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" />
--- /dev/null
+<?php
+class Horde_Injector_Filter_AnnotatedSetterInjectorTest extends PHPUnit_Framework_TestCase
+{
+ public function testAnnotatedSettersAreInjected()
+ {
+ $injector = new Horde_Injector(new Horde_Injector_TopLevel());
+ $foo1 = $injector->createInstance('Horde_Injector_TestFoo');
+ $this->assertNull($foo1->bar);
+
+ $injector->addFilter(new Horde_Injector_Filter_AnnotatedSetterInjector());
+ $foo2 = $injector->createInstance('Horde_Injector_TestFoo');
+ $this->assertType('Horde_Injector_TestBar', $foo2->bar);
+ }
+
+ public function testAnnotatedSettersAreThereWhenCallingGetInstanceAgain()
+ {
+ $injector = new Horde_Injector(new Horde_Injector_TopLevel());
+ $injector->addFilter(new Horde_Injector_Filter_AnnotatedSetterInjector());
+ $foo1 = $injector->getInstance('Horde_Injector_TestFoo');
+
+ $foo2 = $injector->getInstance('Horde_Injector_TestFoo');
+ $this->assertType('Horde_Injector_TestBar', $foo2->bar);
+ }
+}
+
+/**
+ * Used by the preceding tests
+ *
+ * @inject setBar
+ */
+class Horde_Injector_TestFoo
+{
+ public $bar;
+
+ public function setBar(Horde_Injector_TestBar $bar)
+ {
+ $this->bar = $bar;
+ }
+}
+
+class Horde_Injector_TestBar
+{
+}
}
/**
- * Used by preceeding tests!!!
+ * Used by preceding tests
*/
class Horde_Injector_Binder_Mock implements Horde_Injector_Binder
{