From: Chuck Hagenbuch Date: Mon, 26 Apr 2010 00:26:40 +0000 (-0400) Subject: Add object creation filters, and provide one that injects annotated setter dependencies. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=b89acd6e7bc2c2ab7510c24f5706638dcd816af4;p=horde.git Add object creation filters, and provide one that injects annotated setter dependencies. --- diff --git a/framework/Injector/lib/Horde/Injector.php b/framework/Injector/lib/Horde/Injector.php index c37bd273d..4f5fce754 100644 --- a/framework/Injector/lib/Horde/Injector.php +++ b/framework/Injector/lib/Horde/Injector.php @@ -16,6 +16,7 @@ class Horde_Injector implements Horde_Injector_Scope { private $_parentInjector; private $_bindings = array(); + private $_filters = array(); private $_instances; /** @@ -197,7 +198,9 @@ class Horde_Injector implements Horde_Injector_Scope */ public function createInstance($interface) { - return $this->getBinder($interface)->create($this); + $instance = $this->getBinder($interface)->create($this); + $this->runFilters($instance); + return $instance; } /** @@ -235,4 +238,53 @@ 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"); + } + + /** + * 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); + } + } } diff --git a/framework/Injector/lib/Horde/Injector/Binder/Implementation.php b/framework/Injector/lib/Horde/Injector/Binder/Implementation.php index 66928a321..a5c9e597e 100644 --- a/framework/Injector/lib/Horde/Injector/Binder/Implementation.php +++ b/framework/Injector/lib/Horde/Injector/Binder/Implementation.php @@ -79,56 +79,24 @@ class Horde_Injector_Binder_Implementation implements Horde_Injector_Binder /** * 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) ); } } - } diff --git a/framework/Injector/lib/Horde/Injector/Filter.php b/framework/Injector/lib/Horde/Injector/Filter.php new file mode 100644 index 000000000..267d483b9 --- /dev/null +++ b/framework/Injector/lib/Horde/Injector/Filter.php @@ -0,0 +1,20 @@ + + * @author James Pepin + * @author Chuck Hagenbuch + * @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); +} diff --git a/framework/Injector/lib/Horde/Injector/Filter/AnnotatedSetterInjector.php b/framework/Injector/lib/Horde/Injector/Filter/AnnotatedSetterInjector.php new file mode 100644 index 000000000..4abb760d8 --- /dev/null +++ b/framework/Injector/lib/Horde/Injector/Filter/AnnotatedSetterInjector.php @@ -0,0 +1,67 @@ + + * @author James Pepin + * @author Chuck Hagenbuch + * @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) + ); + } + } +} diff --git a/framework/Injector/package.xml b/framework/Injector/package.xml index 7b77ebc29..5fc1d6764 100644 --- a/framework/Injector/package.xml +++ b/framework/Injector/package.xml @@ -63,8 +63,12 @@ + + + + @@ -104,11 +108,13 @@ + + diff --git a/framework/Injector/test/Horde/Injector/Filter/AnnotatedSetterInjectorTest.php b/framework/Injector/test/Horde/Injector/Filter/AnnotatedSetterInjectorTest.php new file mode 100644 index 000000000..aaaa8598e --- /dev/null +++ b/framework/Injector/test/Horde/Injector/Filter/AnnotatedSetterInjectorTest.php @@ -0,0 +1,43 @@ +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 +{ +} diff --git a/framework/Injector/test/Horde/Injector/InjectorTest.php b/framework/Injector/test/Horde/Injector/InjectorTest.php index 7c0a07c20..3ec68fbd4 100644 --- a/framework/Injector/test/Horde/Injector/InjectorTest.php +++ b/framework/Injector/test/Horde/Injector/InjectorTest.php @@ -246,7 +246,7 @@ class Horde_Injector_InjectorTest extends PHPUnit_Framework_TestCase } /** - * Used by preceeding tests!!! + * Used by preceding tests */ class Horde_Injector_Binder_Mock implements Horde_Injector_Binder {