Permalink
Browse files

Merge remote-tracking branch 'ralphschindler/feature/di-inject-depend…

…encies'
  • Loading branch information...
2 parents 61a0b4c + da2b7a2 commit bf57146353f66e84a6a332c4f01fdd77c3b3b616 @EvanDotPro EvanDotPro committed May 8, 2012
Showing with 111 additions and 87 deletions.
  1. +97 −87 library/Zend/Di/Di.php
  2. +14 −0 tests/Zend/Di/DiTest.php
View
@@ -34,8 +34,10 @@ class Di implements DependencyInjectionInterface
protected $references = array();
/**
+ * @param null|DefinitionList $definitions
+ * @param null|InstanceManager $instanceManager
* @param null|Configuration $config
- * @return \Di\Di\DependencyInjector
+ * @return Di
*/
public function __construct(DefinitionList $definitions = null, InstanceManager $instanceManager = null, Configuration $config = null)
{
@@ -59,7 +61,7 @@ public function configure(Configuration $config)
}
/**
- * @param Definition $definition
+ * @param DefinitionList $definition
* @return Di
*/
public function setDefinitionList(DefinitionList $definitions)
@@ -145,8 +147,8 @@ public function get($name, array $params = array())
*/
public function newInstance($name, array $params = array(), $isShared = true)
{
- // localize dependencies (this also will serve as poka-yoke)
- $definitions = $this->definitions;
+ // localize dependencies
+ $definitions = $this->definitions;
$instanceManager = $this->instanceManager();
if ($instanceManager->hasAlias($name)) {
@@ -195,7 +197,7 @@ public function newInstance($name, array $params = array(), $isShared = true)
$name
);
}
- throw new \RuntimeException($msg);
+ throw new Exception\RuntimeException($msg);
}
if ($isShared) {
@@ -206,106 +208,111 @@ public function newInstance($name, array $params = array(), $isShared = true)
}
}
+ $this->handleInjectDependencies($instance, $class, $injectionMethods, $supertypeInjectionMethods, $params, $alias);
+
+ array_pop($this->instanceContext);
+ return $instance;
+ }
+
+ /**
+ * @param object $instance
+ * @param array $params
+ * @return void
+ */
+ public function injectDependencies($instance, array $params = array())
+ {
+ $definitions = $this->definitions();
+ $class = get_class($instance);
+ $injectionMethods = ($definitions->hasClass($class)) ? $definitions->getMethods($class) : array();
+ $superTypeInjectionMethods = array();
+ $parent = $class;
+ while ($parent = get_parent_class($parent)) {
+ if ($definitions->hasClass($parent)) {
+ $superTypeInjectionMethods[$parent] = $definitions->getMethods($parent);
+ }
+ }
+ foreach (class_implements($class) as $interface) {
+ if ($definitions->hasClass($interface)) {
+ $superTypeInjectionMethods[$interface] = $definitions->getMethods($interface);
+ }
+ }
+ $this->handleInjectDependencies($instance, null, $injectionMethods, $superTypeInjectionMethods, $params, null);
+ }
+
+
+ protected function handleInjectDependencies($instance, $name, $injectionMethods, $supertypeInjectionMethods, $params, $alias)
+ {
+ $class = get_class($instance);
+
+ // localize dependencies
+ $definitions = $this->definitions;
+ $instanceManager = $this->instanceManager();
+
if ($injectionMethods || $supertypeInjectionMethods) {
foreach ($injectionMethods as $injectionMethod => $methodIsRequired) {
- if ($injectionMethod !== '__construct') {
- $this->handleInjectionMethodForInstance($instance, $injectionMethod, $params, $alias, $methodIsRequired);
+ if ($injectionMethod !== '__construct'){
+ $this->resolveAndCallInjectionMethodForInstance($instance, $injectionMethod, $params, $alias, $methodIsRequired, $class);
}
}
foreach ($supertypeInjectionMethods as $supertype => $supertypeInjectionMethod) {
foreach ($supertypeInjectionMethod as $injectionMethod => $methodIsRequired) {
if ($injectionMethod !== '__construct') {
- $this->handleInjectionMethodForInstance($instance, $injectionMethod, $params, $alias, $methodIsRequired, $supertype);
+ $this->resolveAndCallInjectionMethodForInstance($instance, $injectionMethod, $params, $alias, $methodIsRequired, $supertype);
}
}
}
- $instanceConfiguration = $instanceManager->getConfiguration($name);
-
- if ($instanceConfiguration['injections']) {
- $objectsToInject = $methodsToCall = array();
- foreach ($instanceConfiguration['injections'] as $injectName => $injectValue) {
- if (is_int($injectName) && is_string($injectValue)) {
- $objectsToInject[] = $this->get($injectValue, $params);
- } elseif (is_string($injectName) && is_array($injectValue)) {
- if (is_string(key($injectValue))) {
- $methodsToCall[] = array('method' => $injectName, 'args' => $injectValue);
- } else {
- foreach ($injectValue as $methodCallArgs) {
- $methodsToCall[] = array('method' => $injectName, 'args' => $methodCallArgs);
+ if ($name) {
+ $instanceConfiguration = $instanceManager->getConfiguration($name);
+
+ if ($instanceConfiguration['injections']) {
+ $objectsToInject = $methodsToCall = array();
+ foreach ($instanceConfiguration['injections'] as $injectName => $injectValue) {
+ if (is_int($injectName) && is_string($injectValue)) {
+ $objectsToInject[] = $this->get($injectValue, $params);
+ } elseif (is_string($injectName) && is_array($injectValue)) {
+ if (is_string(key($injectValue))) {
+ $methodsToCall[] = array('method' => $injectName, 'args' => $injectValue);
+ } else {
+ foreach ($injectValue as $methodCallArgs) {
+ $methodsToCall[] = array('method' => $injectName, 'args' => $methodCallArgs);
+ }
}
+ } elseif (is_object($injectValue)) {
+ $objectsToInject[] = $injectValue;
+ } elseif (is_int($injectName) && is_array($injectValue)) {
+ throw new Exception\RuntimeException(
+ 'An injection was provided with a keyed index and an array of data, try using'
+ . ' the name of a particular method as a key for your injection data.'
+ );
}
- } elseif (is_object($injectValue)) {
- $objectsToInject[] = $injectValue;
- } elseif (is_int($injectName) && is_array($injectValue)) {
- // @todo must find method name somehow
- throw new Exception\RuntimeException(
- 'An injection was provided with a keyed index and an array of data, try using'
- . ' the name of a particular method as a key for your injection data.'
- );
}
- }
- if ($objectsToInject) {
- foreach ($objectsToInject as $objectToInject) {
- foreach ($injectionMethods as $injectionMethod => $methodIsRequired) {
- $methodParams = $definitions->getMethodParameters($class, $injectionMethod);
- if ($methodParams) {
- foreach ($methodParams as $methodParam) {
- if (get_class($objectToInject) == $methodParam[1] ||
- $this->isSubclassOf(get_class($objectToInject), $methodParam[1])) {
- $callParams = $this->resolveMethodParameters(get_class($instance), $injectionMethod,
- array($methodParam[0] => $objectToInject), false, $alias, true
- );
- if ($callParams) {
- call_user_func_array(array($instance, $injectionMethod), $callParams);
+ if ($objectsToInject) {
+ foreach ($objectsToInject as $objectToInject) {
+ foreach ($injectionMethods as $injectionMethod => $methodIsRequired) {
+ $methodParams = $definitions->getMethodParameters($class, $injectionMethod);
+ if ($methodParams) {
+ foreach ($methodParams as $methodParam) {
+ if (get_class($objectToInject) == $methodParam[1] || $this->isSubclassOf(get_class($objectToInject), $methodParam[1])) {
+ $this->resolveAndCallInjectionMethodForInstance($instance, $injectionMethod, array($methodParam[0] => $objectToInject), $alias, true, get_class($instance));
+ continue 3;
}
- continue 3;
}
}
}
}
}
- }
- if ($methodsToCall) {
- foreach ($methodsToCall as $methodInfo) {
- $callParams = $this->resolveMethodParameters(get_class($instance), $methodInfo['method'],
- $methodInfo['args'], false, $alias, true
- );
- call_user_func_array(array($instance, $methodInfo['method']), $callParams);
+ if ($methodsToCall) {
+ foreach ($methodsToCall as $methodInfo) {
+ $this->resolveAndCallInjectionMethodForInstance($instance, $methodInfo['method'], $methodInfo['args'], $alias, true, get_class($instance));
+ }
}
}
}
}
-
-
-
- array_pop($this->instanceContext);
- return $instance;
}
/**
- * @todo
- * @param unknown_type $object
- */
- /*
- public function injectObjects($targetObject, array $objects = array())
- {
- if ($objects === array()) {
- throw new \Exception('Not yet implmeneted');
- }
-
- $targetClass = get_class($targetObject);
- if (!$this->definitions()->hasClass($targetClass)) {
- throw new Exception\RuntimeException('A definition for this object type cannot be found');
- }
-
- foreach ($objects as $objectToInject) {
-
- }
- }
- */
-
- /**
* Retrieve a class instance based on class name
*
* Any parameters provided will be used as constructor arguments. If any
@@ -321,7 +328,7 @@ protected function createInstanceViaConstructor($class, $params, $alias = null)
{
$callParameters = array();
if ($this->definitions->hasMethod($class, '__construct')) {
- $callParameters = $this->resolveMethodParameters($class, '__construct', $params, true, $alias, true);
+ $callParameters = $this->resolveMethodParameters($class, '__construct', $params, $alias, true, true);
}
// Hack to avoid Reflection in most common use cases
@@ -366,7 +373,7 @@ protected function createInstanceViaCallback($callback, $params, $alias)
$callParameters = array();
if ($this->definitions->hasMethod($class, $method)) {
- $callParameters = $this->resolveMethodParameters($class, $method, $params, true, $alias, true);
+ $callParameters = $this->resolveMethodParameters($class, $method, $params, $alias, true, true);
}
return call_user_func_array($callback, $callParameters);
}
@@ -380,11 +387,10 @@ protected function createInstanceViaCallback($callback, $params, $alias)
* @param array $params
* @param string $alias
*/
- protected function handleInjectionMethodForInstance($instance, $method, $params, $alias, $methodIsRequired, $methodClass = null)
+ protected function resolveAndCallInjectionMethodForInstance($instance, $method, $params, $alias, $methodIsRequired, $methodClass = null)
{
$methodClass = ($methodClass) ?: get_class($instance);
- // @todo make sure to resolve the supertypes for both the object & definition
- $callParameters = $this->resolveMethodParameters($methodClass, $method, $params, false, $alias, $methodIsRequired);
+ $callParameters = $this->resolveMethodParameters($methodClass, $method, $params, $alias, $methodIsRequired);
if ($callParameters == false) {
return;
}
@@ -403,7 +409,7 @@ protected function handleInjectionMethodForInstance($instance, $method, $params,
* @param string $alias
* @return array
*/
- protected function resolveMethodParameters($class, $method, array $callTimeUserParams, $isInstantiator, $alias, $methodIsRequired)
+ protected function resolveMethodParameters($class, $method, array $callTimeUserParams, $alias, $methodIsRequired, $isInstantiator = false)
{
// parameters for this method, in proper order, to be returned
$resolvedParams = array();
@@ -433,9 +439,13 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP
}
// for the parent class, provided we are deeper than one node
- list($requestedClass, $requestedAlias) = ($this->instanceContext[0][0] == 'NEW')
- ? array($this->instanceContext[0][1], $this->instanceContext[0][2])
- : array($this->instanceContext[1][1], $this->instanceContext[1][2]);
+ if (isset($this->instanceContext[0])) {
+ list($requestedClass, $requestedAlias) = ($this->instanceContext[0][0] == 'NEW')
+ ? array($this->instanceContext[0][1], $this->instanceContext[0][2])
+ : array($this->instanceContext[1][1], $this->instanceContext[1][2]);
+ } else {
+ $requestedClass = $requestedAlias = null;
+ }
if ($requestedClass != $class && $this->instanceManager->hasConfiguration($requestedClass)) {
$iConfig['requestedClass'] = $this->instanceManager->getConfiguration($requestedClass);
View
@@ -610,4 +610,18 @@ public function testMarkingClassAsNotSharedInjectsNewInstanceIntoAllRequestersBu
$this->assertNotSame($movie->lister, $venue->lister);
$this->assertSame($movie->lister->sharedLister, $venue->lister->sharedLister);
}
+
+ public function testDiWillInjectDependenciesForInstance()
+ {
+ $di = new Di;
+
+ // for setter injection, the dependency is not required, thus it must be forced
+ $classDef = new Definition\ClassDefinition('ZendTest\Di\TestAsset\SetterInjection\B');
+ $classDef->addMethod('setA', true);
+ $di->definitions()->addDefinition($classDef, false); // top of stack b/c Runtime is already there
+
+ $b = new TestAsset\SetterInjection\B;
+ $di->injectDependencies($b);
+ $this->assertInstanceOf('ZendTest\Di\TestAsset\SetterInjection\A', $b->a);
+ }
}

0 comments on commit bf57146

Please sign in to comment.