diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 21d57da5..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tools/phptools"] - path = tools/phptools - url = git://github.com/ralphschindler/PHPTools.git diff --git a/.travis/run-tests.sh b/.travis/run-tests.sh deleted file mode 100755 index a84e0ba2..00000000 --- a/.travis/run-tests.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -travisdir=$(dirname "$0") -testdir="$travisdir/../tests" -testedcomponents=(`cat "$travisdir/tested-components"`) -result=0 - -for tested in "${testedcomponents[@]}" - do - echo "$tested:" - phpunit -c $testdir/phpunit.xml.dist $testdir/$tested - result=$(($result || $?)) -done - -exit $result diff --git a/.travis/skipped-components b/.travis/skipped-components deleted file mode 100644 index 171dfe9d..00000000 --- a/.travis/skipped-components +++ /dev/null @@ -1,7 +0,0 @@ -Zend/Amf -Zend/Date -Zend/Dojo -Zend/Queue -Zend/Service -Zend/Test -Zend/Wildfire diff --git a/.travis/tested-components b/.travis/tested-components deleted file mode 100644 index b0b94380..00000000 --- a/.travis/tested-components +++ /dev/null @@ -1,61 +0,0 @@ -Zend/Acl -Zend/Authentication -Zend/Barcode -Zend/Cache -Zend/Captcha -Zend/Cloud -Zend/Code -Zend/Config -Zend/Console -Zend/Crypt -Zend/Currency -Zend/Db -Zend/Di -Zend/DocBook -Zend/Dojo -Zend/Dom -Zend/EventManager -Zend/Feed -Zend/File -Zend/Filter -Zend/Form -Zend/GData -Zend/Http -Zend/InfoCard -Zend/InputFilter -Zend/Json -Zend/Ldap -Zend/Loader -Zend/Locale -Zend/Log -Zend/Mail -Zend/Markup -Zend/Math -Zend/Measure -Zend/Memory -Zend/Mime -Zend/ModuleManager -Zend/Mvc -Zend/Navigation -Zend/OAuth -Zend/OpenId -Zend/Paginator -Zend/Pdf -Zend/ProgressBar -Zend/RegistryTest.php -Zend/Rest -Zend/Search -Zend/Serializer -Zend/Server -Zend/Session -Zend/Soap -Zend/Stdlib -Zend/Tag -Zend/Text -Zend/TimeSync -Zend/Translator -Zend/Uri -Zend/Validator -Zend/VersionTest.php -Zend/View -Zend/XmlRpc diff --git a/composer.json b/composer.json index ecec11f1..06ffe5a7 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "zendframework/zend-di", - "description": "Zend\\Di component", + "description": " ", "license": "BSD-3-Clause", "keywords": [ "zf2", @@ -9,11 +9,11 @@ "homepage": "https://github.com/zendframework/zend-di", "autoload": { "psr-4": { - "Zend\\Di\\": "src/" + "Zend\\Di": "src/" } }, "require": { - "php": ">=5.3.23", + "php": ">=5.3.3", "zendframework/zend-code": "self.version", "zendframework/zend-stdlib": "self.version" }, diff --git a/src/Configuration.php b/src/Config.php similarity index 81% rename from src/Configuration.php rename to src/Config.php index 855bec97..aa093914 100644 --- a/src/Configuration.php +++ b/src/Config.php @@ -1,21 +1,38 @@ data = $options; } - + + /** + * Configure + * + * @param Di $di + * @return void + */ public function configure(Di $di) { if (isset($this->data['definition'])) { @@ -40,9 +63,13 @@ public function configure(Di $di) if (isset($this->data['instance'])) { $this->configureInstance($di, $this->data['instance']); } - + } + /** + * @param Di $di + * @param array $definition + */ public function configureDefinition(Di $di, $definition) { foreach ($definition as $definitionType => $definitionData) { @@ -50,7 +77,7 @@ public function configureDefinition(Di $di, $definition) case 'compiler': foreach ($definitionData as $filename) { if (is_readable($filename)) { - $di->definitions()->addDefinition(new \Zend\Di\Definition\ArrayDefinition(include $filename), false); + $di->definitions()->addDefinition(new ArrayDefinition(include $filename), false); } } break; @@ -59,16 +86,18 @@ public function configureDefinition(Di $di, $definition) // Remove runtime from definition list if not enabled $definitions = array(); foreach ($di->definitions() as $definition) { - if (!$definition instanceof \Zend\Di\Definition\RuntimeDefinition) { + if (!$definition instanceof RuntimeDefinition) { $definitions[] = $definition; } } $definitions = new DefinitionList($definitions); $di->setDefinitionList($definitions); } elseif (isset($definitionData['use_annotations']) && $definitionData['use_annotations']) { - $di->definitions()->getDefinitionByType('\Zend\Di\Definition\RuntimeDefinition') - ->getIntrospectionStrategy() - ->setUseAnnotations(true); + /* @var $runtimeDefinition Definition\RuntimeDefinition */ + $runtimeDefinition = $di + ->definitions() + ->getDefinitionByType('\Zend\Di\Definition\RuntimeDefinition'); + $runtimeDefinition->getIntrospectionStrategy()->setUseAnnotations(true); } break; case 'class': @@ -121,11 +150,17 @@ public function configureDefinition(Di $di, $definition) } } - + + /** + * Configures a given Di instance + * + * @param Di $di + * @param $instanceData + */ public function configureInstance(Di $di, $instanceData) { $im = $di->instanceManager(); - + foreach ($instanceData as $target => $data) { switch (strtolower($target)) { case 'aliases': @@ -168,5 +203,4 @@ public function configureInstance(Di $di, $instanceData) } - } diff --git a/src/Definition/Annotation/Inject.php b/src/Definition/Annotation/Inject.php index 7f0cc16e..46a0131e 100644 --- a/src/Definition/Annotation/Inject.php +++ b/src/Definition/Annotation/Inject.php @@ -1,14 +1,33 @@ content = $content; diff --git a/src/Definition/Annotation/Instantiator.php b/src/Definition/Annotation/Instantiator.php index ce90de6c..2de9f205 100644 --- a/src/Definition/Annotation/Instantiator.php +++ b/src/Definition/Annotation/Instantiator.php @@ -1,14 +1,33 @@ content = $content; diff --git a/src/Definition/ArrayDefinition.php b/src/Definition/ArrayDefinition.php index 13641fb8..48a53c59 100644 --- a/src/Definition/ArrayDefinition.php +++ b/src/Definition/ArrayDefinition.php @@ -1,13 +1,32 @@ $value) { // force lower names @@ -15,109 +34,134 @@ public function __construct(Array $dataArray) } $this->dataArray = $dataArray; } - + + /** + * {@inheritDoc} + */ public function getClasses() { return array_keys($this->dataArray); } - + + /** + * {@inheritDoc} + */ public function hasClass($class) { return array_key_exists($class, $this->dataArray); } - + + /** + * {@inheritDoc} + */ public function getClassSupertypes($class) { if (!isset($this->dataArray[$class])) { return array(); } - + if (!isset($this->dataArray[$class]['supertypes'])) { return array(); } - + return $this->dataArray[$class]['supertypes']; } - + + /** + * {@inheritDoc} + */ public function getInstantiator($class) { if (!isset($this->dataArray[$class])) { return null; } - + if (!isset($this->dataArray[$class]['instantiator'])) { return '__construct'; } - + return $this->dataArray[$class]['instantiator']; } - + + /** + * {@inheritDoc} + */ public function hasMethods($class) { if (!isset($this->dataArray[$class])) { return array(); } - + if (!isset($this->dataArray[$class]['methods'])) { return array(); } - + return (count($this->dataArray[$class]['methods']) > 0); } - + + /** + * {@inheritDoc} + */ public function hasMethod($class, $method) { if (!isset($this->dataArray[$class])) { return false; } - + if (!isset($this->dataArray[$class]['methods'])) { return false; } - + return array_key_exists($method, $this->dataArray[$class]['methods']); } - + + /** + * {@inheritDoc} + */ public function getMethods($class) { if (!isset($this->dataArray[$class])) { return array(); } - + if (!isset($this->dataArray[$class]['methods'])) { return array(); } - + return $this->dataArray[$class]['methods']; } /** - * @param $class - * @param $method - * @return bool + * {@inheritDoc} */ public function hasMethodParameters($class, $method) { return isset($this->dataArray[$class]['parameters'][$method]); } + /** + * {@inheritDoc} + */ public function getMethodParameters($class, $method) { if (!isset($this->dataArray[$class])) { return array(); } - + if (!isset($this->dataArray[$class]['parameters'])) { return array(); } - + if (!isset($this->dataArray[$class]['parameters'][$method])) { return array(); } - + return $this->dataArray[$class]['parameters'][$method]; } - + + /** + * @return array + */ public function toArray() { return $this->dataArray; diff --git a/src/Definition/Builder/InjectionMethod.php b/src/Definition/Builder/InjectionMethod.php index e9566362..e52f9e99 100644 --- a/src/Definition/Builder/InjectionMethod.php +++ b/src/Definition/Builder/InjectionMethod.php @@ -1,25 +1,58 @@ name = $name; + return $this; } - + + /** + * @return null|string + */ public function getName() { return $this->name; } - + + /** + * @param string $name + * @param string|null $class + * @param mixed|null $isRequired + * @return InjectionMethod + */ public function addParameter($name, $class = null, $isRequired = null) { $this->parameters[] = array( @@ -27,12 +60,16 @@ public function addParameter($name, $class = null, $isRequired = null) $class, ($isRequired == null) ? true : false ); + return $this; } - + + /** + * @return array + */ public function getParameters() { return $this->parameters; } - + } diff --git a/src/Definition/Builder/PhpClass.php b/src/Definition/Builder/PhpClass.php index 5939abeb..f9f1b865 100644 --- a/src/Definition/Builder/PhpClass.php +++ b/src/Definition/Builder/PhpClass.php @@ -1,51 +1,121 @@ name = $name; + return $this; } - + + /** + * Get name + * + * @return string + */ public function getName() { return $this->name; } - + + /** + * @param string|\Callable|array $instantiator + * @return PhpClass + */ public function setInstantiator($instantiator) { $this->instantiator = $instantiator; + return $this; } - + + /** + * @return array|\Callable|string + */ public function getInstantiator() { return $this->instantiator; } - + + /** + * @param string $superType + * @return PhpClass + */ public function addSuperType($superType) { $this->superTypes[] = $superType; + return $this; } - + + /** + * Get super types + * + * @return array + */ public function getSuperTypes() { return $this->superTypes; } - + + /** + * Add injection method + * + * @param InjectionMethod $injectionMethod + * @return PhpClass + */ public function addInjectionMethod(InjectionMethod $injectionMethod) { $this->injectionMethods[] = $injectionMethod; + return $this; } @@ -54,33 +124,36 @@ public function addInjectionMethod(InjectionMethod $injectionMethod) * * Optionally takes the method name. * - * This method may be used in lieu of addInjectionMethod() in + * This method may be used in lieu of addInjectionMethod() in * order to provide a more fluent interface for building classes with * injection methods. - * - * @param null|string $name + * + * @param null|string $name * @return InjectionMethod */ public function createInjectionMethod($name = null) { $builder = $this->defaultMethodBuilder; + /* @var $method InjectionMethod */ $method = new $builder(); if (null !== $name) { $method->setName($name); } $this->addInjectionMethod($method); + return $method; } /** * Override which class will be used by {@link createInjectionMethod()} - * - * @param string $class + * + * @param string $class * @return PhpClass */ public function setMethodBuilder($class) { $this->defaultMethodBuilder = $class; + return $this; } @@ -88,14 +161,17 @@ public function setMethodBuilder($class) * Determine what class will be used by {@link createInjectionMethod()} * * Mainly to provide the ability to temporarily override the class used. - * + * * @return string */ public function getMethodBuilder() { return $this->defaultMethodBuilder; } - + + /** + * @return InjectionMethod[] + */ public function getInjectionMethods() { return $this->injectionMethods; diff --git a/src/Definition/BuilderDefinition.php b/src/Definition/BuilderDefinition.php index 734edc95..fb9ee2d4 100644 --- a/src/Definition/BuilderDefinition.php +++ b/src/Definition/BuilderDefinition.php @@ -1,14 +1,41 @@ $classInfo) { @@ -36,16 +63,23 @@ public function createClassesFromArray(array $builderData) $class->addInjectionMethod($injectionMethod); } break; - + } } $this->addClass($class); } } - + + /** + * Add class + * + * @param Builder\PhpClass $phpClass + * @return BuilderDefinition + */ public function addClass(Builder\PhpClass $phpClass) { $this->classes[] = $phpClass; + return $this; } @@ -53,56 +87,69 @@ public function addClass(Builder\PhpClass $phpClass) * Create a class builder object using default class builder class * * This method is a factory that can be used in place of addClass(). - * - * @param null|string $name Optional name of class to assign + * + * @param null|string $name Optional name of class to assign * @return Builder\PhpClass */ public function createClass($name = null) { $builderClass = $this->defaultClassBuilder; + /* @var $class Builder\PhpClass */ $class = new $builderClass(); + if (null !== $name) { $class->setName($name); } $this->addClass($class); + return $class; } /** * Set the class to use with {@link createClass()} - * - * @param string $class + * + * @param string $class * @return BuilderDefinition */ public function setClassBuilder($class) { $this->defaultClassBuilder = $class; + return $this; } /** * Get the class used for {@link createClass()} * - * This is primarily to allow developers to temporarily override + * This is primarily to allow developers to temporarily override * the builder strategy. - * + * * @return string */ public function getClassBuilder() { return $this->defaultClassBuilder; } - + + /** + * {@inheritDoc} + */ public function getClasses() { $classNames = array(); + + /* @var $class Builder\PhpClass */ foreach ($this->classes as $class) { $classNames[] = $class->getName(); } + return $classNames; } - + + /** + * {@inheritDoc} + */ public function hasClass($class) { foreach ($this->classes as $classObj) { @@ -110,9 +157,14 @@ public function hasClass($class) return true; } } + return false; } - + + /** + * @param string $name + * @return bool|Builder\PhpClass + */ protected function getClass($name) { foreach ($this->classes as $classObj) { @@ -120,37 +172,58 @@ protected function getClass($name) return $classObj; } } + return false; } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function getClassSupertypes($class) { $class = $this->getClass($class); + if ($class === false) { throw new Exception\RuntimeException('Cannot find class object in this builder definition.'); } + return $class->getSuperTypes(); } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function getInstantiator($class) { $class = $this->getClass($class); if ($class === false) { throw new Exception\RuntimeException('Cannot find class object in this builder definition.'); } + return $class->getInstantiator(); } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function hasMethods($class) { - /* @var $class Zend\Di\Definition\Builder\PhpClass */ + /* @var $class \Zend\Di\Definition\Builder\PhpClass */ $class = $this->getClass($class); if ($class === false) { throw new Exception\RuntimeException('Cannot find class object in this builder definition.'); } + return (count($class->getInjectionMethods()) > 0); } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function getMethods($class) { $class = $this->getClass($class); @@ -159,12 +232,19 @@ public function getMethods($class) } $methods = $class->getInjectionMethods(); $methodNames = array(); + + /* @var $methodObj Builder\InjectionMethod */ foreach ($methods as $methodObj) { $methodNames[] = $methodObj->getName(); } + return $methodNames; } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function hasMethod($class, $method) { $class = $this->getClass($class); @@ -172,18 +252,19 @@ public function hasMethod($class, $method) throw new Exception\RuntimeException('Cannot find class object in this builder definition.'); } $methods = $class->getInjectionMethods(); + + /* @var $methodObj Builder\InjectionMethod */ foreach ($methods as $methodObj) { if ($methodObj->getName() === $method) { return true; } } + return false; } /** - * @param $class - * @param $method - * @return bool + * {@inheritDoc} */ public function hasMethodParameters($class, $method) { @@ -192,6 +273,7 @@ public function hasMethodParameters($class, $method) return false; } $methods = $class->getInjectionMethods(); + /* @var $methodObj Builder\InjectionMethod */ foreach ($methods as $methodObj) { if ($methodObj->getName() === $method) { $method = $methodObj; @@ -200,9 +282,16 @@ public function hasMethodParameters($class, $method) if (!$method instanceof Builder\InjectionMethod) { return false; } + + /* @var $method Builder\InjectionMethod */ + return (count($method->getParameters()) > 0); } - + + /** + * {@inheritDoc} + * @throws \Zend\Di\Exception\RuntimeException + */ public function getMethodParameters($class, $method) { $class = $this->getClass($class); @@ -210,6 +299,7 @@ public function getMethodParameters($class, $method) throw new Exception\RuntimeException('Cannot find class object in this builder definition.'); } $methods = $class->getInjectionMethods(); + /* @var $methodObj Builder\InjectionMethod */ foreach ($methods as $methodObj) { if ($methodObj->getName() === $method) { $method = $methodObj; @@ -219,11 +309,12 @@ public function getMethodParameters($class, $method) throw new Exception\RuntimeException('Cannot find method object for method ' . $method . ' in this builder definition.'); } $methodParameters = array(); + /* @var $method Builder\InjectionMethod */ foreach ($method->getParameters() as $name => $info) { $methodParameters[$class->getName() . '::' . $method->getName() . ':' . $name] = $info; } + return $methodParameters; } - } diff --git a/src/Definition/ClassDefinition.php b/src/Definition/ClassDefinition.php index 0f0fe3ce..9249d931 100644 --- a/src/Definition/ClassDefinition.php +++ b/src/Definition/ClassDefinition.php @@ -1,34 +1,83 @@ class = $class; } + /** + * @param null|\Callable|array|string $instantiator + * @return self + */ public function setInstantiator($instantiator) { $this->instantiator = $instantiator; + return $this; } + /** + * @param string[] $supertypes + * @return self + */ public function setSupertypes(array $supertypes) { $this->supertypes = $supertypes; + return $this; } + /** + * @param string $method + * @param bool|null $isRequired + * @return self + */ public function addMethod($method, $isRequired = null) { if ($isRequired === null) { @@ -42,7 +91,8 @@ public function addMethod($method, $isRequired = null) /** * @param $method * @param $parameterName - * @param array $parameterInfo (keys: required, type) + * @param array $parameterInfo (keys: required, type) + * @return ClassDefinition */ public function addMethodParameter($method, $parameterName, array $parameterInfo) { @@ -61,12 +111,12 @@ public function addMethodParameter($method, $parameterName, array $parameterInfo $this->methodParameters[$method][$fqName] = array( $parameterName, $type, $required ); - + return $this; } /** - * @return string[] + * {@inheritDoc} */ public function getClasses() { @@ -74,8 +124,7 @@ public function getClasses() } /** - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasClass($class) { @@ -83,8 +132,7 @@ public function hasClass($class) } /** - * @param string $class - * @return string[] + * {@inheritDoc} */ public function getClassSupertypes($class) { @@ -92,8 +140,7 @@ public function getClassSupertypes($class) } /** - * @param string $class - * @return string|array + * {@inheritDoc} */ public function getInstantiator($class) { @@ -101,8 +148,7 @@ public function getInstantiator($class) } /** - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasMethods($class) { @@ -110,8 +156,7 @@ public function hasMethods($class) } /** - * @param string $class - * @return string[] + * {@inheritDoc} */ public function getMethods($class) { @@ -119,9 +164,7 @@ public function getMethods($class) } /** - * @param string $class - * @param string $method - * @return bool + * {@inheritDoc} */ public function hasMethod($class, $method) { @@ -133,9 +176,7 @@ public function hasMethod($class, $method) } /** - * @param string $class - * @param string $method - * @return bool + * {@inheritDoc} */ public function hasMethodParameters($class, $method) { @@ -143,27 +184,14 @@ public function hasMethodParameters($class, $method) } /** - * getMethodParameters() return information about a methods parameters. - * - * Should return an ordered named array of parameters for a given method. - * Each value should be an array, of length 4 with the following information: - * - * array( - * 0, // string|null: Type Name (if it exists) - * 1, // bool: whether this param is required - * 2, // string: fully qualified path to this parameter - * ); - * - * - * @param $class - * @param $method - * @return array[] + * {@inheritDoc} */ public function getMethodParameters($class, $method) { if (array_key_exists($method, $this->methodParameters)) { return $this->methodParameters[$method]; } + return null; } } diff --git a/src/Definition/CompilerDefinition.php b/src/Definition/CompilerDefinition.php index 0f1b0882..be08fb8c 100644 --- a/src/Definition/CompilerDefinition.php +++ b/src/Definition/CompilerDefinition.php @@ -1,23 +1,37 @@ introspectionStrategy = ($introspectionStrategy) ?: new IntrospectionStrategy(); $this->directoryScanner = new AggregateDirectoryScanner(); } + /** + * Set introspection strategy + * + * @param IntrospectionStrategy $introspectionStrategy + */ public function setIntrospectionStrategy(IntrospectionStrategy $introspectionStrategy) { $this->introspectionStrategy = $introspectionStrategy; } - + + /** + * @param bool $allowReflectionExceptions + */ + public function setAllowReflectionExceptions($allowReflectionExceptions = true) + { + $this->allowReflectionExceptions = (bool) $allowReflectionExceptions; + } + /** - * + * Get introspection strategy + * * @return IntrospectionStrategy */ public function getIntrospectionStrategy() @@ -45,25 +78,45 @@ public function getIntrospectionStrategy() return $this->introspectionStrategy; } + /** + * Add directory + * + * @param string $directory + */ public function addDirectory($directory) { $this->addDirectoryScanner(new DirectoryScanner($directory)); } + /** + * Add directory scanner + * + * @param DirectoryScanner $directoryScanner + */ public function addDirectoryScanner(DirectoryScanner $directoryScanner) { $this->directoryScanner->addDirectoryScanner($directoryScanner); } - + + /** + * Add code scanner file + * + * @param FileScanner $fileScanner + */ public function addCodeScannerFile(FileScanner $fileScanner) { if ($this->directoryScanner == null) { $this->directoryScanner = new DirectoryScanner(); } - + $this->directoryScanner->addFileScanner($fileScanner); } - + + /** + * Compile + * + * @return void + */ public function compile() { /* @var $classScanner \Zend\Code\Scanner\DerivedClassScanner */ @@ -72,6 +125,9 @@ public function compile() } } + /** + * @return ArrayDefinition + */ public function toArrayDefinition() { return new ArrayDefinition( @@ -79,12 +135,23 @@ public function toArrayDefinition() ); } + /** + * @param string $class + * @throws \ReflectionException + */ protected function processClass($class) { $strategy = $this->introspectionStrategy; // localize for readability - /** @var $rClass \Zend\Code\Reflection\ClassReflection */ - $rClass = new Reflection\ClassReflection($class); + try { + $rClass = new Reflection\ClassReflection($class); + } catch (\ReflectionException $e) { + if (!$this->allowReflectionExceptions) { + throw $e; + } + + return; + } $className = $rClass->getName(); $matches = null; // used for regex below @@ -103,11 +170,13 @@ protected function processClass($class) $annotations = $rClass->getAnnotations($strategy->getAnnotationManager()); if (($annotations instanceof AnnotationCollection) - && $annotations->hasAnnotation('Zend\Di\Definition\Annotation\Instantiator')) { - // @todo Instnatiator support in annotations + && $annotations->hasAnnotation('Zend\Di\Definition\Annotation\Instantiator') + ) { + // @todo Instantiator support in annotations } } + /* @var $rTarget \Zend\Code\Reflection\ClassReflection */ $rTarget = $rClass; $supertypes = array(); do { @@ -129,9 +198,16 @@ protected function processClass($class) if ($rClass->hasMethod('__construct')) { $def['methods']['__construct'] = true; // required - $this->processParams($def, $rClass, $rClass->getMethod('__construct')); - } + try { + $this->processParams($def, $rClass, $rClass->getMethod('__construct')); + } catch (\ReflectionException $e) { + if (!$this->allowReflectionExceptions) { + throw $e; + } + return; + } + } foreach ($rClass->getMethods(Reflection\MethodReflection::IS_PUBLIC) as $rMethod) { @@ -145,7 +221,8 @@ protected function processClass($class) $annotations = $rMethod->getAnnotations($strategy->getAnnotationManager()); if (($annotations instanceof AnnotationCollection) - && $annotations->hasAnnotation('Zend\Di\Definition\Annotation\Inject')) { + && $annotations->hasAnnotation('Zend\Di\Definition\Annotation\Inject') + ) { $def['methods'][$methodName] = true; $this->processParams($def, $rClass, $rMethod); @@ -165,7 +242,6 @@ protected function processClass($class) } } - // method // by annotation // by setter pattern, @@ -182,7 +258,8 @@ protected function processClass($class) preg_match($interfaceInjectorPattern, $rIface->getName(), $matches); if ($matches) { foreach ($rIface->getMethods() as $rMethod) { - if ($rMethod->getName() === '__construct') { // ctor not allowed in ifaces + if ($rMethod->getName() === '__construct') { + // constructor not allowed in interfaces continue; } $def['methods'][$rMethod->getName()] = true; @@ -192,11 +269,13 @@ protected function processClass($class) } } } - - - //var_dump($this->classes); } + /** + * @param array $def + * @param \Zend\Code\Reflection\ClassReflection $rClass + * @param \Zend\Code\Reflection\MethodReflection $rMethod + */ protected function processParams(&$def, Reflection\ClassReflection $rClass, Reflection\MethodReflection $rMethod) { if (count($rMethod->getParameters()) === 0) { @@ -315,7 +394,8 @@ protected function processParams(&$def, Reflection\ClassReflection $rClass, Refl // preg_match($interfaceInjectorPattern, $sInterface->getName(), $matches); // if ($matches) { // foreach ($sInterface->getMethods(true) as $sMethod) { -// if ($sMethod->getName() === '__construct') { // ctor not allowed in ifaces +// if ($sMethod->getName() === '__construct') { + // constructor not allowed in interfaces // continue; // } // $def['methods'][$sMethod->getName()] = true; @@ -381,9 +461,7 @@ protected function processParams(&$def, Reflection\ClassReflection $rClass, Refl // } /** - * Return nothing - * - * @return array + * {@inheritDoc} */ public function getClasses() { @@ -391,10 +469,7 @@ public function getClasses() } /** - * Return whether the class exists - * - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasClass($class) { @@ -402,101 +477,86 @@ public function hasClass($class) } /** - * Return the supertypes for this class - * - * @param string $class - * @return array of types + * {@inheritDoc} */ public function getClassSupertypes($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['supertypes']; } /** - * Get the instantiator - * - * @param string $class - * @return string|callable + * {@inheritDoc} */ public function getInstantiator($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['instantiator']; } /** - * Return if there are injection methods - * - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasMethods($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return (count($this->classes[$class]['methods']) > 0); } /** - * Return injection methods - * - * @param string $class - * @param string $method - * @return bool + * {@inheritDoc} */ public function hasMethod($class, $method) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return isset($this->classes[$class]['methods'][$method]); } /** - * Return an array of the injection methods - * - * @param string $class - * @return array + * {@inheritDoc} */ public function getMethods($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['methods']; } + /** + * {@inheritDoc} + */ public function hasMethodParameters($class, $method) { if (!isset($this->classes[$class])) { return false; } + return (array_key_exists($method, $this->classes[$class])); } /** - * Return the parameters for a method - * - * 3 item array: - * #1 - Class name, string if it exists, else null - * #2 - Optional?, boolean - * #3 - Instantiable, boolean if class exists, otherwise null - * - * @param string $class - * @param string $method - * @return array + * {@inheritDoc} */ public function getMethodParameters($class, $method) { if (!is_array($this->classes[$class])) { $this->processClass($class); } + return $this->classes[$class]['parameters'][$method]; } } diff --git a/src/Definition/DefinitionInterface.php b/src/Definition/DefinitionInterface.php index 45ea83a5..a642d9d2 100644 --- a/src/Definition/DefinitionInterface.php +++ b/src/Definition/DefinitionInterface.php @@ -1,54 +1,76 @@ annotationManager = ($annotationManager) ?: $this->createDefaultAnnotationManager(); } + /** + * Get annotation manager + * + * @return null|AnnotationManager + */ public function getAnnotationManager() { return $this->annotationManager; } + /** + * Create default annotation manager + * + * @return AnnotationManager + */ public function createDefaultAnnotationManager() { $annotationManager = new AnnotationManager; - $annotationManager->registerAnnotation(new Annotation\Inject()); + $parser = new GenericAnnotationParser(); + $parser->registerAnnotation(new Annotation\Inject()); + $annotationManager->attach($parser); + return $annotationManager; } - - + /** + * set use annotations + * + * @param bool $useAnnotations + */ public function setUseAnnotations($useAnnotations) { - $this->useAnnotations = $useAnnotations; + $this->useAnnotations = (bool) $useAnnotations; } + /** + * Get use annotations + * + * @return bool + */ public function getUseAnnotations() { return $this->useAnnotations; } - - public function setMethodNameInclusionPatterns($methodNameInclusionPatterns) + /** + * Set method name inclusion pattern + * + * @param array $methodNameInclusionPatterns + */ + public function setMethodNameInclusionPatterns(array $methodNameInclusionPatterns) { $this->methodNameInclusionPatterns = $methodNameInclusionPatterns; } + /** + * Get method name inclusion pattern + * + * @return array + */ public function getMethodNameInclusionPatterns() { return $this->methodNameInclusionPatterns; } - - public function setInterfaceInjectionInclusionPatterns($interfaceInjectionInclusionPatterns) + /** + * Set interface injection inclusion patterns + * + * @param array $interfaceInjectionInclusionPatterns + */ + public function setInterfaceInjectionInclusionPatterns(array $interfaceInjectionInclusionPatterns) { $this->interfaceInjectionInclusionPatterns = $interfaceInjectionInclusionPatterns; } + /** + * Get interface injection inclusion patterns + * + * @return array + */ public function getInterfaceInjectionInclusionPatterns() { return $this->interfaceInjectionInclusionPatterns; diff --git a/src/Definition/PartialMarker.php b/src/Definition/PartialMarker.php index 459b26e5..4a34203b 100644 --- a/src/Definition/PartialMarker.php +++ b/src/Definition/PartialMarker.php @@ -1,8 +1,19 @@ introspectionStrategy = $introspectionStrategy; } - + /** * @return IntrospectionStrategy */ @@ -58,6 +74,11 @@ public function getIntrospectionStrategy() return $this->introspectionStrategy; } + /** + * Set explicit classes + * + * @param array $explicitClasses + */ public function setExplicitClasses(array $explicitClasses) { $this->explicitLookups = true; @@ -67,15 +88,16 @@ public function setExplicitClasses(array $explicitClasses) $this->classes = $explicitClasses; } + /** + * @param string $class + */ public function forceLoadClass($class) { $this->processClass($class); } /** - * Return nothing - * - * @return array + * {@inheritDoc} */ public function getClasses() { @@ -83,119 +105,104 @@ public function getClasses() } /** - * Return whether the class exists - * - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasClass($class) { if ($this->explicitLookups === true) { return (array_key_exists($class, $this->classes)); } - + return class_exists($class) || interface_exists($class); } /** - * Return the supertypes for this class - * - * @param string $class - * @return array of types + * {@inheritDoc} */ public function getClassSupertypes($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['supertypes']; } /** - * Get the instantiator - * - * @param string $class - * @return string|callable + * {@inheritDoc} */ public function getInstantiator($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['instantiator']; } /** - * Return if there are injection methods - * - * @param string $class - * @return bool + * {@inheritDoc} */ public function hasMethods($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return (count($this->classes[$class]['methods']) > 0); } /** - * Return injection methods - * - * @param string $class - * @param string $method - * @return bool + * {@inheritDoc} */ public function hasMethod($class, $method) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return isset($this->classes[$class]['methods'][$method]); } /** - * Return an array of the injection methods - * - * @param string $class - * @return array + * {@inheritDoc} */ public function getMethods($class) { if (!array_key_exists($class, $this->classes)) { $this->processClass($class); } + return $this->classes[$class]['methods']; } + /** + * {@inheritDoc} + */ public function hasMethodParameters($class, $method) { if (!isset($this->classes[$class])) { return false; } + return (array_key_exists($method, $this->classes[$class]['parameters'])); } /** - * Return the parameters for a method - * - * 3 item array: - * #1 - Class name, string if it exists, else null - * #2 - Optional?, boolean - * #3 - Instantiable, boolean if class exists, otherwise null - * - * @param string $class - * @param string $method - * @return array + * {@inheritDoc} */ public function getMethodParameters($class, $method) { if (!is_array($this->classes[$class])) { $this->processClass($class); } + return $this->classes[$class]['parameters'][$method]; } + /** + * @param string $class + */ protected function processClass($class) { $strategy = $this->introspectionStrategy; // localize for readability @@ -221,7 +228,7 @@ protected function processClass($class) if (($annotations instanceof AnnotationCollection) && $annotations->hasAnnotation('Zend\Di\Definition\Annotation\Instantiator')) { - // @todo Instnatiator support in annotations + // @todo Instantiator support in annotations } } @@ -249,7 +256,6 @@ protected function processClass($class) $this->processParams($def, $rClass, $rClass->getMethod('__construct')); } - foreach ($rClass->getMethods(Reflection\MethodReflection::IS_PUBLIC) as $rMethod) { $methodName = $rMethod->getName(); @@ -282,7 +288,6 @@ protected function processClass($class) } } - // method // by annotation // by setter pattern, @@ -299,7 +304,8 @@ protected function processClass($class) preg_match($interfaceInjectorPattern, $rIface->getName(), $matches); if ($matches) { foreach ($rIface->getMethods() as $rMethod) { - if ($rMethod->getName() === '__construct') { // ctor not allowed in ifaces + if ($rMethod->getName() === '__construct') { + // constructor not allowed in interfaces continue; } $def['methods'][$rMethod->getName()] = true; @@ -309,11 +315,13 @@ protected function processClass($class) } } } - - - //var_dump($this->classes); } + /** + * @param array $def + * @param \Zend\Code\Reflection\ClassReflection $rClass + * @param \Zend\Code\Reflection\MethodReflection $rMethod + */ protected function processParams(&$def, Reflection\ClassReflection $rClass, Reflection\MethodReflection $rMethod) { if (count($rMethod->getParameters()) === 0) { diff --git a/src/DefinitionList.php b/src/DefinitionList.php index 22c504d8..47061f3b 100644 --- a/src/DefinitionList.php +++ b/src/DefinitionList.php @@ -1,12 +1,28 @@ push($definition); } } - + + /** + * Add definitions + * + * @param Definition\DefinitionInterface $definition + * @param bool $addToBackOfList + * @return void + */ public function addDefinition(Definition\DefinitionInterface $definition, $addToBackOfList = true) { if ($addToBackOfList) { @@ -27,7 +50,7 @@ public function addDefinition(Definition\DefinitionInterface $definition, $addTo } /** - * @param string $type + * @param string $type * @return Definition[] */ public function getDefinitionsByType($type) @@ -38,12 +61,15 @@ public function getDefinitionsByType($type) $definitions[] = $definition; } } + return $definitions; } /** - * @param string $type - * @return Definition + * Get definition by type + * + * @param string $type + * @return Definition\DefinitionInterface */ public function getDefinitionByType($type) { @@ -52,9 +78,14 @@ public function getDefinitionByType($type) return $definition; } } + return false; } + /** + * @param string $class + * @return bool|Definition\DefinitionInterface + */ public function getDefinitionForClass($class) { /** @var $definition Definition\DefinitionInterface */ @@ -63,15 +94,22 @@ public function getDefinitionForClass($class) return $definition; } } + return false; } + /** + * @param string $class + * @return bool|Definition\DefinitionInterface + */ public function forClass($class) { return $this->getDefinitionForClass($class); } - + /** + * {@inheritDoc} + */ public function getClasses() { $classes = array(); @@ -79,9 +117,13 @@ public function getClasses() foreach ($this as $definition) { $classes = array_merge($classes, $definition->getClasses()); } + return $classes; } - + + /** + * {@inheritDoc} + */ public function hasClass($class) { /** @var $definition Definition\DefinitionInterface */ @@ -90,9 +132,13 @@ public function hasClass($class) return true; } } + return false; } - + + /** + * {@inheritDoc} + */ public function getClassSupertypes($class) { $supertypes = array(); @@ -103,7 +149,10 @@ public function getClassSupertypes($class) // @todo remove duplicates? return $supertypes; } - + + /** + * {@inheritDoc} + */ public function getInstantiator($class) { /** @var $definition Definition\DefinitionInterface */ @@ -117,9 +166,13 @@ public function getInstantiator($class) } } } + return false; } - + + /** + * {@inheritDoc} + */ public function hasMethods($class) { /** @var $definition Definition\DefinitionInterface */ @@ -132,9 +185,13 @@ public function hasMethods($class) } } } + return false; } - + + /** + * {@inheritDoc} + */ public function hasMethod($class, $method) { /** @var $definition Definition\DefinitionInterface */ @@ -147,9 +204,13 @@ public function hasMethod($class, $method) } } } + return false; } - + + /** + * {@inheritDoc} + */ public function getMethods($class) { /** @var $definition Definition\DefinitionInterface */ @@ -163,15 +224,23 @@ public function getMethods($class) } } } + return $methods; } + /** + * {@inheritDoc} + */ public function hasMethodParameters($class, $method) { $methodParameters = $this->getMethodParameters($class, $method); + return ($methodParameters !== array()); } + /** + * {@inheritDoc} + */ public function getMethodParameters($class, $method) { /** @var $definition Definition\DefinitionInterface */ @@ -180,7 +249,8 @@ public function getMethodParameters($class, $method) return $definition->getMethodParameters($class, $method); } } + return array(); } - + } diff --git a/src/DependencyInjectionInterface.php b/src/DependencyInjectionInterface.php index e09c3e57..dedf955c 100644 --- a/src/DependencyInjectionInterface.php +++ b/src/DependencyInjectionInterface.php @@ -1,7 +1,19 @@ definitions = ($definitions) ?: new DefinitionList(new Definition\RuntimeDefinition()); $this->instanceManager = ($instanceManager) ?: new InstanceManager(); @@ -52,21 +70,22 @@ public function __construct(DefinitionList $definitions = null, InstanceManager /** * Provide a configuration object to configure this instance * - * @param Configuration $config + * @param Config $config * @return void */ - public function configure(Configuration $config) + public function configure(Config $config) { $config->configure($this); } /** - * @param DefinitionList $definition - * @return Di + * @param DefinitionList $definitions + * @return self */ public function setDefinitionList(DefinitionList $definitions) { $this->definitions = $definitions; + return $this; } @@ -81,12 +100,13 @@ public function definitions() /** * Set the instance manager * - * @param InstanceManager $instanceManager + * @param InstanceManager $instanceManager * @return Di */ public function setInstanceManager(InstanceManager $instanceManager) { $this->instanceManager = $instanceManager; + return $this; } @@ -99,7 +119,6 @@ public function instanceManager() return $this->instanceManager; } - /** * Lazy-load a class * @@ -107,8 +126,8 @@ public function instanceManager() * loaded before, the previous instance will be returned (unless the service * definition indicates shared instances should not be used). * - * @param string $name Class name or service alias - * @param null|array $params Parameters to pass to the constructor + * @param string $name Class name or service alias + * @param null|array $params Parameters to pass to the constructor * @return object|null */ public function get($name, array $params = array()) @@ -121,16 +140,19 @@ public function get($name, array $params = array()) $fastHash = $im->hasSharedInstanceWithParameters($name, $params, true); if ($fastHash) { array_pop($this->instanceContext); + return $im->getSharedInstanceWithParameters(null, array(), $fastHash); } } else { if ($im->hasSharedInstance($name, $params)) { array_pop($this->instanceContext); + return $im->getSharedInstance($name, $params); } } $instance = $this->newInstance($name, $params); array_pop($this->instanceContext); + return $instance; } @@ -140,10 +162,12 @@ public function get($name, array $params = array()) * Forces retrieval of a discrete instance of the given class, using the * constructor parameters provided. * - * @param mixed $name Class name or service alias - * @param array $params Parameters to pass to the constructor - * @param bool $isShared + * @param mixed $name Class name or service alias + * @param array $params Parameters to pass to the constructor + * @param bool $isShared * @return object|null + * @throws Exception\ClassNotFoundException + * @throws Exception\RuntimeException */ public function newInstance($name, array $params = array(), $isShared = true) { @@ -211,18 +235,21 @@ public function newInstance($name, array $params = array(), $isShared = true) $this->handleInjectDependencies($instance, $injectionMethods, $params, $class, $alias, $name); array_pop($this->instanceContext); + return $instance; } /** - * @param object $instance - * @param array $params + * Inject dependencies + * + * @param object $instance + * @param array $params * @return void */ public function injectDependencies($instance, array $params = array()) { $definitions = $this->definitions(); - $class = get_class($instance); + $class = $this->getClass($instance); $injectionMethods = array( $class => ($definitions->hasClass($class)) ? $definitions->getMethods($class) : array() ); @@ -240,7 +267,15 @@ public function injectDependencies($instance, array $params = array()) $this->handleInjectDependencies($instance, $injectionMethods, $params, $class, null, null); } - + /** + * @param object $instance + * @param array $injectionMethods + * @param array $params + * @param string|null $instanceClass + * @param string|null$instanceAlias + * @param string $requestedName + * @throws Exception\RuntimeException + */ protected function handleInjectDependencies($instance, $injectionMethods, $params, $instanceClass, $instanceAlias, $requestedName) { // localize dependencies @@ -261,11 +296,11 @@ protected function handleInjectDependencies($instance, $injectionMethods, $param } if ($requestedName) { - $instanceConfiguration = $instanceManager->getConfiguration($requestedName); + $instanceConfig = $instanceManager->getConfig($requestedName); - if ($instanceConfiguration['injections']) { + if ($instanceConfig['injections']) { $objectsToInject = $methodsToCall = array(); - foreach ($instanceConfiguration['injections'] as $injectName => $injectValue) { + foreach ($instanceConfig['injections'] as $injectName => $injectValue) { if (is_int($injectName) && is_string($injectValue)) { $objectsToInject[] = $this->get($injectValue, $params); } elseif (is_string($injectName) && is_array($injectValue)) { @@ -294,7 +329,8 @@ protected function handleInjectDependencies($instance, $injectionMethods, $param $methodParams = $definitions->getMethodParameters($type, $typeInjectionMethod); if ($methodParams) { foreach ($methodParams as $methodParam) { - if (get_class($objectToInject) == $methodParam[1] || $this->isSubclassOf(get_class($objectToInject), $methodParam[1])) { + $objectToInjectClass = $this->getClass($objectToInject); + if ($objectToInjectClass == $methodParam[1] || self::isSubclassOf($objectToInjectClass, $methodParam[1])) { if ($this->resolveAndCallInjectionMethodForInstance($instance, $typeInjectionMethod, array($methodParam[0] => $objectToInject), $instanceAlias, true, $type)) { $calledMethods[$typeInjectionMethod] = true; } @@ -309,7 +345,7 @@ protected function handleInjectDependencies($instance, $injectionMethods, $param } if ($methodsToCall) { foreach ($methodsToCall as $methodInfo) { - $this->resolveAndCallInjectionMethodForInstance($instance, $methodInfo['method'], $methodInfo['args'], $instanceAlias, true, get_class($instance)); + $this->resolveAndCallInjectionMethodForInstance($instance, $methodInfo['method'], $methodInfo['args'], $instanceAlias, true, $instanceClass); } } } @@ -324,9 +360,9 @@ protected function handleInjectDependencies($instance, $injectionMethods, $param * given parameter is a DependencyReference object, it will be fetched * from the container so that the instance may be injected. * - * @param string $class - * @param array $params - * @param string|null $alias + * @param string $class + * @param array $params + * @param string|null $alias * @return object */ protected function createInstanceViaConstructor($class, $params, $alias = null) @@ -348,6 +384,7 @@ protected function createInstanceViaConstructor($class, $params, $alias = null) return new $class($callParameters[0], $callParameters[1], $callParameters[2]); default: $r = new \ReflectionClass($class); + return $r->newInstanceArgs($callParameters); } } @@ -355,11 +392,12 @@ protected function createInstanceViaConstructor($class, $params, $alias = null) /** * Get an object instance from the defined callback * - * @param callback $callback - * @param array $params - * @param string $alias + * @param callback $callback + * @param array $params + * @param string $alias * @return object * @throws Exception\InvalidCallbackException + * @throws Exception\RuntimeException */ protected function createInstanceViaCallback($callback, $params, $alias) { @@ -368,7 +406,7 @@ protected function createInstanceViaCallback($callback, $params, $alias) } if (is_array($callback)) { - $class = (is_object($callback[0])) ? get_class($callback[0]) : $callback[0]; + $class = (is_object($callback[0])) ? $this->getClass($callback[0]) : $callback[0]; $method = $callback[1]; } elseif (is_string($callback) && strpos($callback, '::') !== false) { list($class, $method) = explode('::', $callback, 2); @@ -380,6 +418,7 @@ protected function createInstanceViaCallback($callback, $params, $alias) if ($this->definitions->hasMethod($class, $method)) { $callParameters = $this->resolveMethodParameters($class, $method, $params, $alias, true, true); } + return call_user_func_array($callback, $callParameters); } @@ -387,33 +426,41 @@ protected function createInstanceViaCallback($callback, $params, $alias) * This parameter will handle any injection methods and resolution of * dependencies for such methods * - * @param object $object - * @param string $method - * @param array $params - * @param string $alias + * @param object $instance + * @param string $method + * @param array $params + * @param string $alias + * @param bool $methodIsRequired + * @param string|null $methodClass + * @return bool */ protected function resolveAndCallInjectionMethodForInstance($instance, $method, $params, $alias, $methodIsRequired, $methodClass = null) { - $methodClass = ($methodClass) ?: get_class($instance); + $methodClass = ($methodClass) ?: $this->getClass($instance); $callParameters = $this->resolveMethodParameters($methodClass, $method, $params, $alias, $methodIsRequired); if ($callParameters == false) { return false; } if ($callParameters !== array_fill(0, count($callParameters), null)) { call_user_func_array(array($instance, $method), $callParameters); + return true; } + return false; } /** * Resolve parameters referencing other services * - * @param string $class - * @param string $method - * @param array $callTimeUserParams - * @param bool $isInstantiator - * @param string $alias + * @param string $class + * @param string $method + * @param array $callTimeUserParams + * @param string $alias + * @param bool $methodIsRequired + * @param bool $isInstantiator + * @throws Exception\MissingPropertyException + * @throws Exception\CircularDependencyException * @return array */ protected function resolveMethodParameters($class, $method, array $callTimeUserParams, $alias, $methodIsRequired, $isInstantiator = false) @@ -436,13 +483,13 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP $aliases = $this->instanceManager->getAliases(); // for the alias in the dependency tree - if ($alias && $this->instanceManager->hasConfiguration($alias)) { - $iConfig['thisAlias'] = $this->instanceManager->getConfiguration($alias); + if ($alias && $this->instanceManager->hasConfig($alias)) { + $iConfig['thisAlias'] = $this->instanceManager->getConfig($alias); } // for the current class in the dependency tree - if ($this->instanceManager->hasConfiguration($class)) { - $iConfig['thisClass'] = $this->instanceManager->getConfiguration($class); + if ($this->instanceManager->hasConfig($class)) { + $iConfig['thisClass'] = $this->instanceManager->getConfig($class); } // for the parent class, provided we are deeper than one node @@ -454,10 +501,10 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP $requestedClass = $requestedAlias = null; } - if ($requestedClass != $class && $this->instanceManager->hasConfiguration($requestedClass)) { - $iConfig['requestedClass'] = $this->instanceManager->getConfiguration($requestedClass); + if ($requestedClass != $class && $this->instanceManager->hasConfig($requestedClass)) { + $iConfig['requestedClass'] = $this->instanceManager->getConfig($requestedClass); if ($requestedAlias) { - $iConfig['requestedAlias'] = $this->instanceManager->getConfiguration($requestedAlias); + $iConfig['requestedAlias'] = $this->instanceManager->getConfig($requestedAlias); } } @@ -481,7 +528,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP $callTimeCurValue =& $callTimeUserParams[$name]; } - if (is_string($callTimeCurValue)) { + if ($type !== false && is_string($callTimeCurValue)) { if ($this->instanceManager->hasAlias($callTimeCurValue)) { // was an alias provided? $computedParams['required'][$fqParamPos] = array( @@ -525,8 +572,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP $iConfigCurValue =& $iConfig[$thisIndex]['parameters'][$name]; } - if (is_string($iConfigCurValue) - && $type === false) { + if ($type === false && is_string($iConfigCurValue)) { $computedParams['value'][$fqParamPos] = $iConfigCurValue; } elseif (is_string($iConfigCurValue) && isset($aliases[$iConfigCurValue])) { @@ -541,8 +587,9 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP $iConfigCurValue ); } elseif (is_object($iConfigCurValue) - && $iConfigCurValue instanceof \Closure + && $iConfigCurValue instanceof Closure && $type !== 'Closure') { + /* @var $iConfigCurValue Closure */ $computedParams['value'][$fqParamPos] = $iConfigCurValue(); } else { $computedParams['value'][$fqParamPos] = $iConfigCurValue; @@ -565,7 +612,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP } $pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ? $this->instanceManager->getClassFromAlias($pInstance) : $pInstance; - if ($pInstanceClass === $type || $this->isSubclassOf($pInstanceClass, $type)) { + if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) { $computedParams['required'][$fqParamPos] = array($pInstance, $pInstanceClass); continue 2; } @@ -582,7 +629,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP } $pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ? $this->instanceManager->getClassFromAlias($pInstance) : $pInstance; - if ($pInstanceClass === $type || $this->isSubclassOf($pInstanceClass, $type)) { + if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) { $computedParams['required'][$fqParamPos] = array($pInstance, $pInstanceClass); continue 2; } @@ -617,7 +664,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP ); } array_push($this->currentDependencies, $class); - $dConfig = $this->instanceManager->getConfiguration($computedParams['required'][$fqParamPos][0]); + $dConfig = $this->instanceManager->getConfig($computedParams['required'][$fqParamPos][0]); if ($dConfig['shared'] === false) { $resolvedParams[$index] = $this->newInstance($computedParams['required'][$fqParamPos][0], $callTimeUserParams, false); } else { @@ -650,25 +697,43 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP } /** + * Utility method used to retrieve the class of a particular instance. This is here to allow extending classes to + * override how class names are resolved + * + * @internal this method is used by the ServiceLocator\DependencyInjectorProxy class to interact with instances + * and is a hack to be used internally until a major refactor does not split the `resolveMethodParameters`. Do not + * rely on its functionality. + * @param Object $instance + * @return string + */ + protected function getClass($instance) + { + return get_class($instance); + } + + /** + * Checks if the object has this class as one of its parents + * * @see https://bugs.php.net/bug.php?id=53727 + * @see https://github.com/zendframework/zf2/pull/1807 * - * @param $class + * @param string $className * @param $type * @return bool */ - protected function isSubclassOf($class, $type) + protected static function isSubclassOf($className, $type) { - /* @var $isSubclassFunc Closure */ - static $isSubclassFuncCache = null; // null as unset, array when set - - if ($isSubclassFuncCache === null) { - $isSubclassFuncCache = array(); + if (is_subclass_of($className, $type)) { + return true; } - - if (!array_key_exists($class, $isSubclassFuncCache)) { - $isSubclassFuncCache[$class] = class_parents($class, true) + class_implements($class, true); + if (version_compare(PHP_VERSION, '5.3.7', '>=')) { + return false; } - return (isset($isSubclassFuncCache[$class][$type])); - } + if (!interface_exists($type)) { + return false; + } + $r = new ReflectionClass($className); + return $r->implementsInterface($type); + } } diff --git a/src/Display/Console.php b/src/Display/Console.php index dbdb7fc7..6e587945 100644 --- a/src/Display/Console.php +++ b/src/Display/Console.php @@ -1,8 +1,23 @@ render($di); } + /** + * Constructor + * + * @param null|Di $di + */ public function __construct(Di $di = null) { $this->di = ($di) ?: new Di; } + /** + * @param string[] $runtimeClasses + */ public function addRuntimeClasses(array $runtimeClasses) { foreach ($runtimeClasses as $runtimeClass) { @@ -31,12 +65,14 @@ public function addRuntimeClasses(array $runtimeClasses) } } + /** + * @param string $runtimeClass + */ public function addRuntimeClass($runtimeClass) { $this->runtimeClasses[] = $runtimeClass; } - public function render() { @@ -64,7 +100,6 @@ public function render() $this->renderClassDefinition($definition, $runtimeClass); } - echo PHP_EOL . 'Instance Configuration Info:' . PHP_EOL; echo PHP_EOL . ' Aliases:' . PHP_EOL; @@ -83,7 +118,7 @@ public function render() } echo PHP_EOL . ' Configurations:' . PHP_EOL; - + foreach ($configuredTypes as $type) { $info = $this->di->instanceManager()->getConfiguration($type); echo ' ' . $type . PHP_EOL; @@ -105,6 +140,9 @@ public function render() } + /** + * @param object $definition + */ protected function renderDefinition($definition) { echo ' Definition Type: ' . get_class($definition) . PHP_EOL; @@ -122,6 +160,10 @@ protected function renderDefinition($definition) } } + /** + * @param \Zend\Di\Definition\DefinitionInterface $definition + * @param string $class + */ protected function renderClassDefinition($definition, $class) { echo PHP_EOL . ' Parameters For Class: ' . $class . PHP_EOL; diff --git a/src/Exception/CircularDependencyException.php b/src/Exception/CircularDependencyException.php index 7662078f..c9bb0df5 100644 --- a/src/Exception/CircularDependencyException.php +++ b/src/Exception/CircularDependencyException.php @@ -1,8 +1,21 @@ array(), 'hashLong' => array()); - + /** * Array of class aliases * @var array key: alias, value: class */ protected $aliases = array(); - + /** * The template to use for housing configuration information - * @var array + * @var array */ protected $configurationTemplate = array( - /** + /** * alias|class => alias|class * interface|abstract => alias|class|object * name => value @@ -48,22 +62,23 @@ class InstanceManager /* implements InstanceManagerInterface */ * @var array */ protected $configurations = array(); - + /** * An array of globally preferred implementations for interfaces/abstracts * @var array */ protected $typePreferences = array(); - + /** * Does this instance manager have this shared instance + * @param string $classOrAlias * @return bool */ public function hasSharedInstance($classOrAlias) { return isset($this->sharedInstances[$classOrAlias]); } - + /** * getSharedInstance() */ @@ -71,9 +86,13 @@ public function getSharedInstance($classOrAlias) { return $this->sharedInstances[$classOrAlias]; } - + /** - * addSharedInstance() + * Add shared instance + * + * @param object $instance + * @param string $classOrAlias + * @throws Exception\InvalidArgumentException */ public function addSharedInstance($instance, $classOrAlias) { @@ -87,30 +106,31 @@ public function addSharedInstance($instance, $classOrAlias) /** * hasSharedInstanceWithParameters() * - * @param string $classOrAlias - * @param array $params - * @param bool $returnFashHashLookupKey + * @param string $classOrAlias + * @param array $params + * @param bool $returnFastHashLookupKey * @return bool|string */ - public function hasSharedInstanceWithParameters($classOrAlias, array $params, $returnFashHashLookupKey = false) + public function hasSharedInstanceWithParameters($classOrAlias, array $params, $returnFastHashLookupKey = false) { ksort($params); $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params)); if (isset($this->sharedInstancesWithParams['hashShort'][$hashKey])) { $hashValue = $this->createHashForValues($classOrAlias, $params); if (isset($this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue])) { - return ($returnFashHashLookupKey) ? $hashKey . '/' . $hashValue : true; + return ($returnFastHashLookupKey) ? $hashKey . '/' . $hashValue : true; } } + return false; } /** * addSharedInstanceWithParameters() * - * @param object $instance - * @param string $classOrAlias - * @param array $params + * @param object $instance + * @param string $classOrAlias + * @param array $params * @return void */ public function addSharedInstanceWithParameters($instance, $classOrAlias, array $params) @@ -118,8 +138,8 @@ public function addSharedInstanceWithParameters($instance, $classOrAlias, array ksort($params); $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params)); $hashValue = $this->createHashForValues($classOrAlias, $params); - - if (!isset($this->sharedInstancesWithParams[$hashKey]) + + if (!isset($this->sharedInstancesWithParams[$hashKey]) || !is_array($this->sharedInstancesWithParams[$hashKey])) { $this->sharedInstancesWithParams[$hashKey] = array(); } @@ -127,13 +147,21 @@ public function addSharedInstanceWithParameters($instance, $classOrAlias, array $this->sharedInstancesWithParams['hashShort'][$hashKey] = true; $this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue] = $instance; } - + + /** + * Retrieves an instance by its name and the parameters stored at its instantiation + * + * @param string $classOrAlias + * @param array $params + * @param bool|null $fastHashFromHasLookup + * @return object|bool false if no instance was found + */ public function getSharedInstanceWithParameters($classOrAlias, array $params, $fastHashFromHasLookup = null) { if ($fastHashFromHasLookup) { return $this->sharedInstancesWithParams['hashLong'][$fastHashFromHasLookup]; } - + ksort($params); $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params)); if (isset($this->sharedInstancesWithParams['hashShort'][$hashKey])) { @@ -142,25 +170,37 @@ public function getSharedInstanceWithParameters($classOrAlias, array $params, $f return $this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue]; } } + return false; } - - + + /** + * Check for an alias + * + * @param string $alias + * @return bool + */ public function hasAlias($alias) { return (isset($this->aliases[$alias])); } - + + /** + * Get aliases + * + * @return array + */ public function getAliases() { return $this->aliases; } - + /** * getClassFromAlias() * * @param string - * @return bool + * @return string|bool + * @throws Exception\RuntimeException */ public function getClassFromAlias($alias) { @@ -177,9 +217,15 @@ public function getClassFromAlias($alias) ); } } + return $alias; } - + + /** + * @param string $alias + * @return string|bool + * @throws Exception\RuntimeException + */ protected function getBaseAlias($alias) { if (!$this->hasAlias($alias)) { @@ -194,19 +240,20 @@ protected function getBaseAlias($alias) if ($r > 100) { throw new Exception\RuntimeException( sprintf('Possible infinite recursion in DI alias! Max recursion of 100 levels reached at alias "%s".', $alias) - ); + ); } } + return $lastAlias; } - + /** - * addAlias() + * Add alias * * @throws Exception\InvalidArgumentException - * @param $alias - * @param $class - * @param array $parameters + * @param string $alias + * @param string $class + * @param array $parameters * @return void */ public function addAlias($alias, $class, array $parameters = array()) @@ -221,8 +268,14 @@ public function addAlias($alias, $class, array $parameters = array()) $this->setParameters($alias, $parameters); } } - - public function hasConfiguration($aliasOrClass) + + /** + * Check for configuration + * + * @param string $aliasOrClass + * @return bool + */ + public function hasConfig($aliasOrClass) { $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass; if (!isset($this->configurations[$key])) { @@ -231,10 +284,18 @@ public function hasConfiguration($aliasOrClass) if ($this->configurations[$key] === $this->configurationTemplate) { return false; } + return true; } - - public function setConfiguration($aliasOrClass, array $configuration, $append = false) + + /** + * Sets configuration for a single alias/class + * + * @param string $aliasOrClass + * @param array $configuration + * @param bool $append + */ + public function setConfig($aliasOrClass, array $configuration, $append = false) { $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass; if (!isset($this->configurations[$key]) || !$append) { @@ -249,6 +310,11 @@ public function setConfiguration($aliasOrClass, array $configuration, $append = $this->configurations[$key] = array_replace_recursive($this->configurations[$key], $configuration); } + /** + * Get classes + * + * @return array + */ public function getClasses() { $classes = array(); @@ -256,78 +322,128 @@ public function getClasses() if (strpos($name, 'alias') === 0) continue; $classes[] = $name; } + return $classes; } - public function getConfiguration($aliasOrClass) + /** + * @param string $aliasOrClass + * @return array + */ + public function getConfig($aliasOrClass) { $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass; if (isset($this->configurations[$key])) { - return $this->configurations[$key]; + return $this->configurations[$key]; } else { return $this->configurationTemplate; } } - + /** * setParameters() is a convenience method for: - * setConfiguration($type, array('parameters' => array(...)), true); - * - * @param string $type Alias or Class - * @param array $parameters Multi-dim array of parameters and their values + * setConfig($type, array('parameters' => array(...)), true); + * + * @param string $aliasOrClass Alias or Class + * @param array $parameters Multi-dim array of parameters and their values + * @return void */ public function setParameters($aliasOrClass, array $parameters) { - $this->setConfiguration($aliasOrClass, array('parameters' => $parameters), true); + $this->setConfig($aliasOrClass, array('parameters' => $parameters), true); } - + /** * setInjections() is a convenience method for: - * setConfiguration($type, array('injections' => array(...)), true); - * - * @param string $type Alias or Class - * @param array $methods Multi-dim array of methods and their parameters + * setConfig($type, array('injections' => array(...)), true); + * + * @param string $aliasOrClass Alias or Class + * @param array $injections Multi-dim array of methods and their parameters + * @return void */ public function setInjections($aliasOrClass, array $injections) { - $this->setConfiguration($aliasOrClass, array('injections' => $injections), true); + $this->setConfig($aliasOrClass, array('injections' => $injections), true); } + /** + * Set shared + * + * @param string $aliasOrClass + * @param bool $isShared + * @return void + */ public function setShared($aliasOrClass, $isShared) { - $this->setConfiguration($aliasOrClass, array('shared' => $isShared), true); + $this->setConfig($aliasOrClass, array('shared' => (bool) $isShared), true); } + /** + * Check for type preferences + * + * @param string $interfaceOrAbstract + * @return bool + */ public function hasTypePreferences($interfaceOrAbstract) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; + return (isset($this->typePreferences[$key]) && $this->typePreferences[$key]); } + /** + * Set type preference + * + * @param string $interfaceOrAbstract + * @param array $preferredImplementations + * @return InstanceManager + */ public function setTypePreference($interfaceOrAbstract, array $preferredImplementations) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; foreach ($preferredImplementations as $preferredImplementation) { $this->addTypePreference($key, $preferredImplementation); } + return $this; } + /** + * Get type preferences + * + * @param string $interfaceOrAbstract + * @return array + */ public function getTypePreferences($interfaceOrAbstract) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; if (isset($this->typePreferences[$key])) { return $this->typePreferences[$key]; } + return array(); } - + + /** + * Unset type preferences + * + * @param string $interfaceOrAbstract + * @return void + */ public function unsetTypePreferences($interfaceOrAbstract) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; unset($this->typePreferences[$key]); } + /** + * Adds a type preference. A type preference is a redirection to a preferred alias or type when an abstract type + * $interfaceOrAbstract is requested + * + * @param string $interfaceOrAbstract + * @param string $preferredImplementation + * @return self + */ public function addTypePreference($interfaceOrAbstract, $preferredImplementation) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; @@ -335,9 +451,17 @@ public function addTypePreference($interfaceOrAbstract, $preferredImplementation $this->typePreferences[$key] = array(); } $this->typePreferences[$key][] = $preferredImplementation; + return $this; } + /** + * Removes a previously set type preference + * + * @param string $interfaceOrAbstract + * @param string $preferredType + * @return bool|self + */ public function removeTypePreference($interfaceOrAbstract, $preferredType) { $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract; @@ -345,15 +469,25 @@ public function removeTypePreference($interfaceOrAbstract, $preferredType) return false; } unset($this->typePreferences[$key][array_search($key, $this->typePreferences)]); + return $this; } - + /** + * @param string $classOrAlias + * @param string[] $paramKeys + * @return string + */ protected function createHashForKeys($classOrAlias, $paramKeys) { return $classOrAlias . ':' . implode('|', $paramKeys); } - + + /** + * @param string $classOrAlias + * @param array $paramValues + * @return string + */ protected function createHashForValues($classOrAlias, $paramValues) { $hashValue = ''; @@ -377,6 +511,7 @@ protected function createHashForValues($classOrAlias, $paramValues) break; } } + return $hashValue; } } diff --git a/src/LocatorInterface.php b/src/LocatorInterface.php index 71483737..88ee6fc5 100644 --- a/src/LocatorInterface.php +++ b/src/LocatorInterface.php @@ -1,13 +1,26 @@ @@ -16,49 +32,46 @@ class ServiceLocator implements ServiceLocatorInterface * * When encountered, the return value of that method will be used. * - * Methods mapped in this way may expect a single, array argument, the + * Methods mapped in this way may expect a single, array argument, the * $params passed to {@link get()}, if any. - * + * * @var array */ protected $map = array(); /** * Registered services and cached values - * + * * @var array */ protected $services = array(); /** - * Register a service with the locator - * - * @param string $name - * @param mixed $service - * @return ServiceLocator + * {@inheritDoc} */ public function set($name, $service) { $this->services[$name] = $service; + return $this; } /** * Retrieve a registered service * - * Tests first if a value is registered for the service, and, if so, + * Tests first if a value is registered for the service, and, if so, * returns it. * * If the value returned is a non-object callback or closure, the return - * value is retrieved, stored, and returned. Parameters passed to the method + * value is retrieved, stored, and returned. Parameters passed to the method * are passed to the callback, but only on the first retrieval. * * If the service requested matches a method in the method map, the return * value of that method is returned. Parameters are passed to the matching * method. - * - * @param string $name - * @param array $params + * + * @param string $name + * @param array $params * @return mixed */ public function get($name, array $params = array()) @@ -68,11 +81,12 @@ public function get($name, array $params = array()) return null; } $method = $this->map[$name]; + return $this->$method($params); } $service = $this->services[$name]; - if ($service instanceof \Closure + if ($service instanceof Closure || (!is_object($service) && is_callable($service)) ) { $this->services[$name] = $service = call_user_func_array($service, $params); diff --git a/src/ServiceLocator/DependencyInjectorProxy.php b/src/ServiceLocator/DependencyInjectorProxy.php index 3202e169..c6056170 100644 --- a/src/ServiceLocator/DependencyInjectorProxy.php +++ b/src/ServiceLocator/DependencyInjectorProxy.php @@ -1,10 +1,25 @@ instanceManager(); + $instance = parent::newInstance($name, $params, $isShared); - if ($params) { - $fastHash = $im->hasSharedInstanceWithParameters($name, $params, true); - if ($fastHash) { - return $im->getSharedInstanceWithParameters(null, array(), $fastHash); - } - } else { - if ($im->hasSharedInstance($name, $params)) { - return $im->getSharedInstance($name, $params); + if ($instance instanceof GeneratorInstance) { + /* @var $instance GeneratorInstance */ + $instance->setShared($isShared); + + // When a callback is used, we don't know instance the class name. + // That's why we assume $name as the instance alias + if (null === $instance->getName()) { + $instance->setAlias($name); } } - return $this->newInstance($name, $params); + + return $instance; } /** - * Override createInstanceViaConstructor method from injector - * - * Returns code generation artifacts. - * - * @param string $class - * @param null|array $params - * @param null|string $alias + * {@inheritDoc} * @return GeneratorInstance */ public function createInstanceViaConstructor($class, $params, $alias = null) { $callParameters = array(); + if ($this->di->definitions->hasMethod($class, '__construct') && (count($this->di->definitions->getMethodParameters($class, '__construct')) > 0) ) { - $callParameters = $this->resolveMethodParameters( - $class, '__construct', $params, true, $alias, true - ); + $callParameters = $this->resolveMethodParameters($class, '__construct', $params, $alias, true, true); + $callParameters = $callParameters ?: array(); } - return new GeneratorInstance($class, '__construct', $callParameters); + + return new GeneratorInstance($class, $alias, '__construct', $callParameters); } /** - * Override instance creation via callback - * - * @param callback $callback - * @param null|array $params + * {@inheritDoc} + * @throws \Zend\Di\Exception\InvalidCallbackException * @return GeneratorInstance */ - public function createInstanceViaCallback($callback, $params, $alias = null) + public function createInstanceViaCallback($callback, $params, $alias) { + if (is_string($callback)) { + $callback = explode('::', $callback); + } + if (!is_callable($callback)) { throw new Exception\InvalidCallbackException('An invalid constructor callback was provided'); } if (!is_array($callback) || is_object($callback[0])) { - throw new Exception\InvalidCallbackException('For purposes of service locator generation, constructor callbacks must refer to static methods only'); + throw new Exception\InvalidCallbackException( + 'For purposes of service locator generation, constructor callbacks must refer to static methods only' + ); } $class = $callback[0]; @@ -95,87 +112,61 @@ public function createInstanceViaCallback($callback, $params, $alias = null) $callParameters = array(); if ($this->di->definitions->hasMethod($class, $method)) { - $callParameters = $this->resolveMethodParameters($class, $method, $params, true, $alias, true); + $callParameters = $this->resolveMethodParameters($class, $method, $params, $alias, true, true); } - return new GeneratorInstance(null, $callback, $callParameters); + $callParameters = $callParameters ?: array(); + + return new GeneratorInstance(null, $alias, $callback, $callParameters); } /** - * Retrieve metadata for injectible methods - * - * @param string $class - * @param string $method - * @param array $params - * @param string $alias - * @return array + * {@inheritDoc} */ public function handleInjectionMethodForObject($class, $method, $params, $alias, $isRequired) { - $callParameters = $this->resolveMethodParameters($class, $method, $params, false, $alias, $isRequired); return array( 'method' => $method, - 'params' => $callParameters, + 'params' => $this->resolveMethodParameters($class, $method, $params, $alias, $isRequired), ); } /** - * Override new instance creation - * - * @param string $name - * @param array $params - * @param bool $isShared - * @return GeneratorInstance + * {@inheritDoc} */ - public function newInstance($name, array $params = array(), $isShared = true) + protected function resolveAndCallInjectionMethodForInstance($instance, $method, $params, $alias, $methodIsRequired, $methodClass = null) { - $definition = $this->definitions(); - $instanceManager = $this->instanceManager(); - - if ($instanceManager->hasAlias($name)) { - $class = $instanceManager->getClassFromAlias($name); - $alias = $name; - } else { - $class = $name; - $alias = null; + if (!$instance instanceof GeneratorInstance) { + return parent::resolveAndCallInjectionMethodForInstance($instance, $method, $params, $alias, $methodIsRequired, $methodClass); } - if (!$definition->hasClass($class)) { - $aliasMsg = ($alias) ? '(specified by alias ' . $alias . ') ' : ''; - throw new Exception\ClassNotFoundException( - 'Class ' . $aliasMsg . $class . ' could not be located in provided definitions.' - ); - } + /* @var $instance GeneratorInstance */ + $methodClass = $instance->getClass(); + $callParameters = $this->resolveMethodParameters($methodClass, $method, $params, $alias, $methodIsRequired); - $instantiator = $definition->getInstantiator($class); - $injectionMethods = $definition->getMethods($class); + if ($callParameters !== false) { + $instance->addMethod(array( + 'method' => $method, + 'params' => $callParameters, + )); - if ($instantiator === '__construct') { - $object = $this->createInstanceViaConstructor($class, $params, $alias); - if (in_array('__construct', $injectionMethods)) { - unset($injectionMethods[array_search('__construct', $injectionMethods)]); - } - } elseif (is_callable($instantiator)) { - $object = $this->createInstanceViaCallback($instantiator, $params, $alias); - $object->setName($class); - } else { - throw new Exception\RuntimeException('Invalid instantiator'); + return true; } - if ($injectionMethods) { - foreach ($injectionMethods as $injectionMethod) { - $methodMetadata[] = $this->handleInjectionMethodForObject($class, $injectionMethod, $params, $alias); - } - } + return false; + } - if ($isShared) { - if ($params) { - $instanceManager->addSharedInstanceWithParameters($object, $name, $params); - } else { - $instanceManager->addSharedInstance($object, $name); - } + /** + * {@inheritDoc} + */ + protected function getClass($instance) + { + if ($instance instanceof GeneratorInstance) { + /* @var $instance GeneratorInstance */ + + return $instance->getClass(); } - return $object; + return parent::getClass($instance); } } diff --git a/src/ServiceLocator/Generator.php b/src/ServiceLocator/Generator.php index 743f7ddc..5e088987 100644 --- a/src/ServiceLocator/Generator.php +++ b/src/ServiceLocator/Generator.php @@ -1,13 +1,28 @@ containerClass = $name; + return $this; } /** * Set the namespace to use for the generated class file - * - * @param string $namespace + * + * @param string $namespace * @return Generator */ public function setNamespace($namespace) { $this->namespace = $namespace; + return $this; } /** - * Construct, configure, and return a PHP classfile code generation object + * Construct, configure, and return a PHP class file code generation object * - * Creates a Zend\CodeGenerator\Php\PhpFile object that has + * Creates a Zend\CodeGenerator\Php\PhpFile object that has * created the specified class and service locator methods. - * - * @param null|string $filename - * @return CodeGen\FileGenerator + * + * @param null|string $filename + * @throws \Zend\Di\Exception\RuntimeException + * @return FileGenerator */ public function getCodeGenerator($filename = null) { @@ -73,11 +91,13 @@ public function getCodeGenerator($filename = null) $getters = array(); $definitions = $injector->definitions(); - foreach ($definitions->getClasses() as $name) { + $fetched = array_unique(array_merge($definitions->getClasses(), $im->getAliases())); + + foreach ($fetched as $name) { $getter = $this->normalizeAlias($name); $meta = $injector->get($name); $params = $meta->getParams(); - + // Build parameter list for instantiation foreach ($params as $key => $param) { if (null === $param || is_scalar($param) || is_array($param)) { @@ -87,6 +107,7 @@ public function getCodeGenerator($filename = null) } $params[$key] = $string; } elseif ($param instanceof GeneratorInstance) { + /* @var $param GeneratorInstance */ $params[$key] = sprintf('$this->%s()', $this->normalizeAlias($param->getName())); } else { $message = sprintf('Unable to use object arguments when building containers. Encountered with "%s", parameter of type "%s"', $name, get_class($param)); @@ -105,7 +126,6 @@ public function getCodeGenerator($filename = null) } // Create instantiation code - $creation = ''; $constructor = $meta->getConstructor(); if ('__construct' != $constructor) { // Constructor callback @@ -187,9 +207,9 @@ public function getCodeGenerator($filename = null) // End getter body $getterBody .= "return \$object;\n"; - $getterDef = new CodeGen\MethodGenerator(); - $getterDef->setName($getter) - ->setBody($getterBody); + $getterDef = new MethodGenerator(); + $getterDef->setName($getter); + $getterDef->setBody($getterBody); $getters[] = $getterDef; // Get cases for case statements @@ -214,14 +234,14 @@ public function getCodeGenerator($filename = null) $switch .= "}\n\n"; // Build get() method - $nameParam = new CodeGen\ParameterGenerator(); + $nameParam = new ParameterGenerator(); $nameParam->setName('name'); - $paramsParam = new CodeGen\ParameterGenerator(); + $paramsParam = new ParameterGenerator(); $paramsParam->setName('params') ->setType('array') ->setDefaultValue(array()); - $get = new CodeGen\MethodGenerator(); + $get = new MethodGenerator(); $get->setName('get'); $get->setParameters(array( $nameParam, @@ -238,7 +258,7 @@ public function getCodeGenerator($filename = null) } // Create class code generation object - $container = new CodeGen\ClassGenerator(); + $container = new ClassGenerator(); $container->setName($this->containerClass) ->setExtendedClass('ServiceLocator') ->addMethodFromGenerator($get) @@ -246,7 +266,7 @@ public function getCodeGenerator($filename = null) ->addMethods($aliasMethods); // Create PHP file code generation object - $classFile = new CodeGen\FileGenerator(); + $classFile = new FileGenerator(); $classFile->setUse('Zend\Di\ServiceLocator') ->setClass($container); @@ -264,11 +284,11 @@ public function getCodeGenerator($filename = null) /** * Reduces aliases * - * Takes alias list and reduces it to a 2-dimensional array of - * class names pointing to an array of aliases that resolve to + * Takes alias list and reduces it to a 2-dimensional array of + * class names pointing to an array of aliases that resolve to * it. - * - * @param array $aliasList + * + * @param array $aliasList * @return array */ protected function reduceAliases(array $aliasList) @@ -286,35 +306,38 @@ protected function reduceAliases(array $aliasList) } $reduced[$service][] = $alias; } + return $reduced; } /** * Create a PhpMethod code generation object named after a given alias - * - * @param string $alias - * @param class $class Class to which alias refers - * @return CodeGen\MethodGenerator + * + * @param string $alias + * @param string $class Class to which alias refers + * @return MethodGenerator */ protected function getCodeGenMethodFromAlias($alias, $class) { $alias = $this->normalizeAlias($alias); - $method = new CodeGen\MethodGenerator(); - $method->setName($alias) - ->setBody(sprintf('return $this->get(\'%s\');', $class)); + $method = new MethodGenerator(); + $method->setName($alias); + $method->setBody(sprintf('return $this->get(\'%s\');', $class)); + return $method; } /** * Normalize an alias to a getter method name - * - * @param string $alias + * + * @param string $alias * @return string */ protected function normalizeAlias($alias) { $normalized = preg_replace('/[^a-zA-Z0-9]/', ' ', $alias); $normalized = 'get' . str_replace(' ', '', ucwords($normalized)); + return $normalized; } } diff --git a/src/ServiceLocator/GeneratorInstance.php b/src/ServiceLocator/GeneratorInstance.php index 7bc992dc..ef5e64ca 100644 --- a/src/ServiceLocator/GeneratorInstance.php +++ b/src/ServiceLocator/GeneratorInstance.php @@ -1,59 +1,200 @@ name = $name; + $this->class = $class; + $this->alias = $alias; $this->constructor = $constructor; $this->params = $params; } + /** + * Retrieves the best available name for this instance (instance alias first then class name) + * + * @return string|null + */ public function getName() { - return $this->name; + return $this->alias ? $this->alias : $this->class; + } + + /** + * Class of the instance. Null if class is unclear (such as when the instance is produced by a callback) + * + * @return string|null + */ + public function getClass() + { + return $this->class; + } + + /** + * Alias for the instance (if any) + * + * @return string|null + */ + public function getAlias() + { + return $this->alias; } /** * Set class name * - * In the case of an instance created via a callback, we need to set the + * In the case of an instance created via a callback, we need to set the * class name after creating the generator instance. - * - * @param string $name + * + * @param string $class * @return GeneratorInstance */ - public function setName($name) + public function setClass($class) { - $this->name = $name; + $this->class = $class; + return $this; } + /** + * Set instance alias + * + * @param string $alias + * @return GeneratorInstance + */ + public function setAlias($alias) + { + $this->alias = $alias; + + return $this; + } + + /** + * Get instantiator + * + * @return mixed constructor method name or callable responsible for generating instance + */ public function getConstructor() { return $this->constructor; } + /** + * Parameters passed to the instantiator as an ordered list of parameters. Each parameter that refers to another + * instance fetched recursively is a GeneratorInstance itself + * + * @return array + */ public function getParams() { return $this->params; } + /** + * Set methods + * + * @param array $methods + * @return GeneratorInstance + */ public function setMethods(array $methods) { $this->methods = $methods; + return $this; } + /** + * Add a method called on the instance + * + * @param $method + * @return GeneratorInstance + */ + public function addMethod($method) + { + $this->methods[] = $method; + + return $this; + } + + /** + * Retrieves a list of methods that are called on the instance in their call order. Each returned element has form + * array('method' => 'methodName', 'params' => array( ... ordered list of call parameters ... ), where every call + * parameter that is a recursively fetched instance is a GeneratorInstance itself + * + * @return array + */ public function getMethods() { return $this->methods; } + + /** + * @param bool $shared + */ + public function setShared($shared) + { + $this->shared = (bool) $shared; + } + + /** + * Retrieves whether the instance is shared or not + * + * @return bool + */ + public function isShared() + { + return $this->shared; + } } diff --git a/src/ServiceLocatorInterface.php b/src/ServiceLocatorInterface.php index ca773bd0..283c7ba9 100644 --- a/src/ServiceLocatorInterface.php +++ b/src/ServiceLocatorInterface.php @@ -1,7 +1,28 @@ get('section-a'); - $config = new Configuration($ini->di); + $config = new Config($ini->di); $di = new Di(); $di->configure($config); $im = $di->instanceManager(); - + $this->assertTrue($im->hasAlias('my-repository')); $this->assertEquals('My\RepositoryA', $im->getClassFromAlias('my-repository')); - + $this->assertTrue($im->hasAlias('my-mapper')); $this->assertEquals('My\Mapper', $im->getClassFromAlias('my-mapper')); - + $this->assertTrue($im->hasAlias('my-dbAdapter')); $this->assertEquals('My\DbAdapter', $im->getClassFromAlias('my-dbAdapter')); - + $this->assertTrue($im->hasTypePreferences('my-repository')); $this->assertContains('my-mapper', $im->getTypePreferences('my-repository')); - + $this->assertTrue($im->hasTypePreferences('my-mapper')); $this->assertContains('my-dbAdapter', $im->getTypePreferences('my-mapper')); - $this->assertTrue($im->hasConfiguration('My\DbAdapter')); + $this->assertTrue($im->hasConfig('My\DbAdapter')); $expected = array('parameters' => array('username' => 'readonly', 'password' => 'mypassword'), 'injections' => array(), 'shared' => true); - $this->assertEquals($expected, $im->getConfiguration('My\DbAdapter')); - - $this->assertTrue($im->hasConfiguration('my-dbAdapter')); + $this->assertEquals($expected, $im->getConfig('My\DbAdapter')); + + $this->assertTrue($im->hasConfig('my-dbAdapter')); $expected = array('parameters' => array('username' => 'readwrite'), 'injections' => array(), 'shared' => true); - $this->assertEquals($expected, $im->getConfiguration('my-dbAdapter')); + $this->assertEquals($expected, $im->getConfig('my-dbAdapter')); } - - public function testConfigurationCanConfigureBuilderDefinitionFromIni() + + public function testConfigCanConfigureBuilderDefinitionFromIni() { $this->markTestIncomplete('Builder not updated to new DI yet'); $ini = ConfigFactory::fromFile(__DIR__ . '/_files/sample.ini', true)->get('section-b'); - $config = new Configuration($ini->di); + $config = new Config($ini->di); $di = new Di($config); $definition = $di->getDefinition(); - + $this->assertTrue($definition->hasClass('My\DbAdapter')); $this->assertEquals('__construct', $definition->getInstantiator('My\DbAdapter')); $this->assertEquals( array('username' => null, 'password' => null), $definition->getInjectionMethodParameters('My\DbAdapter', '__construct') ); - + $this->assertTrue($definition->hasClass('My\Mapper')); $this->assertEquals('__construct', $definition->getInstantiator('My\Mapper')); $this->assertEquals( array('dbAdapter' => 'My\DbAdapter'), $definition->getInjectionMethodParameters('My\Mapper', '__construct') ); - + $this->assertTrue($definition->hasClass('My\Repository')); $this->assertEquals('__construct', $definition->getInstantiator('My\Repository')); $this->assertEquals( array('mapper' => 'My\Mapper'), $definition->getInjectionMethodParameters('My\Repository', '__construct') ); - + } - public function testConfigurationCanConfigureRuntimeDefinitionDefaultFromIni() + public function testConfigCanConfigureRuntimeDefinitionDefaultFromIni() { $ini = ConfigFactory::fromFile(__DIR__ . '/_files/sample.ini', true)->get('section-c'); - $config = new Configuration($ini->di); + $config = new Config($ini->di); $di = new Di(); $di->configure($config); $definition = $di->definitions()->getDefinitionByType('Zend\Di\Definition\RuntimeDefinition'); @@ -84,30 +92,30 @@ public function testConfigurationCanConfigureRuntimeDefinitionDefaultFromIni() $this->assertFalse($definition->getIntrospectionStrategy()->getUseAnnotations()); } - public function testConfigurationCanConfigureRuntimeDefinitionDisabledFromIni() + public function testConfigCanConfigureRuntimeDefinitionDisabledFromIni() { $ini = ConfigFactory::fromFile(__DIR__ . '/_files/sample.ini', true)->get('section-d'); - $config = new Configuration($ini->di); + $config = new Config($ini->di); $di = new Di(); $di->configure($config); $definition = $di->definitions()->getDefinitionByType('Zend\Di\Definition\RuntimeDefinition'); $this->assertFalse($definition); } - public function testConfigurationCanConfigureRuntimeDefinitionUseAnnotationFromIni() + public function testConfigCanConfigureRuntimeDefinitionUseAnnotationFromIni() { $ini = ConfigFactory::fromFile(__DIR__ . '/_files/sample.ini', true)->get('section-e'); - $config = new Configuration($ini->di); + $config = new Config($ini->di); $di = new Di(); $di->configure($config); $definition = $di->definitions()->getDefinitionByType('Zend\Di\Definition\RuntimeDefinition'); $this->assertTrue($definition->getIntrospectionStrategy()->getUseAnnotations()); } - public function testConfigurationCanConfigureCompiledDefinition() + public function testConfigCanConfigureCompiledDefinition() { $config = ConfigFactory::fromFile(__DIR__ . '/_files/sample.php', true); - $config = new Configuration($config->di); + $config = new Config($config->di); $di = new Di(); $di->configure($config); $definition = $di->definitions()->getDefinitionByType('Zend\Di\Definition\ArrayDefinition'); diff --git a/test/Definition/ArrayDefinitionTest.php b/test/Definition/ArrayDefinitionTest.php index 76e82e3c..be5528d2 100644 --- a/test/Definition/ArrayDefinitionTest.php +++ b/test/Definition/ArrayDefinitionTest.php @@ -1,23 +1,31 @@ definition = new ArrayDefinition(include __DIR__ . '/../_files/definition-array.php'); } - + public function testArrayDefinitionHasClasses() { $this->assertTrue($this->definition->hasClass('My\DbAdapter')); @@ -27,7 +35,7 @@ public function testArrayDefinitionHasClasses() $this->assertTrue($this->definition->hasClass('My\RepositoryB')); $this->assertFalse($this->definition->hasClass('My\Foo')); } - + public function testArrayDefinitionCanGetClassses() { $list = array( @@ -37,38 +45,38 @@ public function testArrayDefinitionCanGetClassses() 'My\RepositoryA', 'My\RepositoryB' ); - + $classes = $this->definition->getClasses(); - + foreach ($list as $class) { $this->assertContains($class, $classes); } - + } - + public function testArrayDefinitionCanGetClassSupertypes() { $this->assertEquals(array(), $this->definition->getClassSupertypes('My\EntityA')); $this->assertContains('My\RepositoryA', $this->definition->getClassSupertypes('My\RepositoryB')); } - - + + public function testArrayDefinitionCanGetInstantiator() { $this->assertEquals('__construct', $this->definition->getInstantiator('My\RepositoryA')); $this->assertNull($this->definition->getInstantiator('My\Foo')); } - + public function testArrayDefinitionHasInjectionMethods() { $this->markTestIncomplete(); } - + public function testArrayDefinitionHasInjectionMethod() { $this->markTestIncomplete(); } - + public function testArrayDefinitionGetInjectionMethods() { $this->markTestIncomplete(); @@ -79,6 +87,6 @@ public function testArrayDefinitionGetInjectionMethodParameters() $this->markTestIncomplete(); } - - + + } diff --git a/test/Definition/BuilderDefinitionTest.php b/test/Definition/BuilderDefinitionTest.php index 5e006510..45acce5f 100644 --- a/test/Definition/BuilderDefinitionTest.php +++ b/test/Definition/BuilderDefinitionTest.php @@ -1,36 +1,44 @@ assertInstanceOf('Zend\Di\Definition\DefinitionInterface', $builder); } - + public function testBuilderCanBuildClassWithMethods() { $class = new Builder\PhpClass(); $class->setName('Foo'); $class->addSuperType('Parent'); - + $injectionMethod = new Builder\InjectionMethod(); $injectionMethod->setName('injectBar'); $injectionMethod->addParameter('bar', 'Bar'); - + $class->addInjectionMethod($injectionMethod); - + $definition = new BuilderDefinition(); $definition->addClass($class); - + $this->assertTrue($definition->hasClass('Foo')); $this->assertEquals('__construct', $definition->getInstantiator('Foo')); $this->assertContains('Parent', $definition->getClassSupertypes('Foo')); @@ -42,17 +50,17 @@ public function testBuilderCanBuildClassWithMethods() $definition->getMethodParameters('Foo', 'injectBar') ); } - + public function testBuilderCanBuildFromArray() { $ini = ConfigFactory::fromFile(__DIR__ . '/../_files/sample.ini'); $iniAsArray = $ini['section-b']; $definitionArray = $iniAsArray['di']['definitions'][1]; unset($definitionArray['class']); - + $definition = new BuilderDefinition(); $definition->createClassesFromArray($definitionArray); - + $this->assertTrue($definition->hasClass('My\DbAdapter')); $this->assertEquals('__construct', $definition->getInstantiator('My\DbAdapter')); $this->assertEquals( @@ -62,21 +70,21 @@ public function testBuilderCanBuildFromArray() ), $definition->getMethodParameters('My\DbAdapter', '__construct') ); - + $this->assertTrue($definition->hasClass('My\Mapper')); $this->assertEquals('__construct', $definition->getInstantiator('My\Mapper')); $this->assertEquals( array('My\Mapper::__construct:0' => array('dbAdapter', 'My\DbAdapter', true)), $definition->getMethodParameters('My\Mapper', '__construct') ); - + $this->assertTrue($definition->hasClass('My\Repository')); $this->assertEquals('__construct', $definition->getInstantiator('My\Repository')); $this->assertEquals( array('My\Repository::__construct:0' => array('mapper', 'My\Mapper', true)), $definition->getMethodParameters('My\Repository', '__construct') ); - + } public function testCanCreateClassFromFluentInterface() @@ -86,7 +94,7 @@ public function testCanCreateClassFromFluentInterface() $this->assertTrue($builder->hasClass('Foo')); } - + public function testCanCreateInjectionMethodsAndPopulateFromFluentInterface() { $builder = new BuilderDefinition(); diff --git a/test/Definition/CompilerDefinitionTest.php b/test/Definition/CompilerDefinitionTest.php index e2be05b4..27a18833 100644 --- a/test/Definition/CompilerDefinitionTest.php +++ b/test/Definition/CompilerDefinitionTest.php @@ -1,11 +1,19 @@ compile(); $this->assertTrue($definition->hasClass('ZendTest\Di\TestAsset\CompilerClasses\A')); - + $assertClasses = array( 'ZendTest\Di\TestAsset\CompilerClasses\A', 'ZendTest\Di\TestAsset\CompilerClasses\B', @@ -30,14 +38,14 @@ public function testCompilerCompilesAgainstConstructorInjectionAssets() // @todo this needs to be resolved, not the short name // $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\C', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\D')); - + $this->assertEquals('__construct', $definition->getInstantiator('ZendTest\Di\TestAsset\CompilerClasses\A')); $this->assertTrue($definition->hasMethods('ZendTest\Di\TestAsset\CompilerClasses\C')); - + $this->assertArrayHasKey('setB', $definition->getMethods('ZendTest\Di\TestAsset\CompilerClasses\C')); $this->assertTrue($definition->hasMethod('ZendTest\Di\TestAsset\CompilerClasses\C', 'setB')); - + $this->assertEquals( array('ZendTest\Di\TestAsset\CompilerClasses\C::setB:0' => array('b', 'ZendTest\Di\TestAsset\CompilerClasses\B', true)), $definition->getMethodParameters('ZendTest\Di\TestAsset\CompilerClasses\C', 'setB') @@ -56,7 +64,7 @@ public function testCompilerSupertypes() $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\C', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\D', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); } - + public function testCompilerDirectoryScannerAndFileScanner() { $definition = new CompilerDefinition; @@ -67,7 +75,7 @@ public function testCompilerDirectoryScannerAndFileScanner() $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\C', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\D', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); } - + public function testCompilerFileScanner() { $definition = new CompilerDefinition; @@ -79,4 +87,24 @@ public function testCompilerFileScanner() $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\C', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); $this->assertContains('ZendTest\Di\TestAsset\CompilerClasses\D', $definition->getClassSupertypes('ZendTest\Di\TestAsset\CompilerClasses\E')); } + + public function testCompilerReflectionException() + { + $this->setExpectedException('ReflectionException', 'Class ZendTest\Di\TestAsset\InvalidCompilerClasses\Foo does not exist'); + $definition = new CompilerDefinition; + $definition->addDirectory(__DIR__ . '/../TestAsset/InvalidCompilerClasses'); + $definition->compile(); + } + + public function testCompilerAllowReflectionException() + { + $definition = new CompilerDefinition; + $definition->setAllowReflectionExceptions(); + $definition->addDirectory(__DIR__ . '/../TestAsset/InvalidCompilerClasses'); + $definition->compile(); + $parameters = $definition->getMethodParameters('ZendTest\Di\TestAsset\InvalidCompilerClasses\InvalidClass', '__construct'); + + // The exception gets caught before the parameter's class is set + $this->assertCount(1, current($parameters)); + } } diff --git a/test/Definition/RuntimeDefinitionTest.php b/test/Definition/RuntimeDefinitionTest.php index 23bb73eb..6fefb699 100644 --- a/test/Definition/RuntimeDefinitionTest.php +++ b/test/Definition/RuntimeDefinitionTest.php @@ -1,9 +1,17 @@ assertSame($dl, $di->definitions()); @@ -147,7 +155,7 @@ public function testNewInstanceCanHandleComplexCallback() // public function testCanSetInstantiatorToStaticFactory() // { -// $config = new Configuration(array( +// $config = new Config(array( // 'definition' => array( // 'class' => array( // 'ZendTest\Di\TestAsset\DummyParams' => array( @@ -597,7 +605,7 @@ public function testInjectionForSetterInjectionWillConsultSupertypeDefinitionInC public function testMarkingClassAsNotSharedInjectsNewInstanceIntoAllRequestersButDependentsAreShared() { $di = new Di(); - $di->configure(new Configuration(array( + $di->configure(new Config(array( 'instance' => array( 'ZendTest\Di\TestAsset\SharedInstance\Lister' => array( 'shared' => false @@ -664,4 +672,25 @@ public function testInjectionForSetterInjectionWillNotUseSupertypeWhenChildParam $c = $di->get('ZendTest\Di\TestAsset\InheritanceClasses\C'); $this->assertEquals('b', $c->test); } + + /** + * @group ZF2-260 + */ + public function testDiWillInjectClassNameAsStringAtCallTime() + { + $di = new Di; + + $classDef = new Definition\ClassDefinition('ZendTest\Di\TestAsset\SetterInjection\D'); + $classDef->addMethod('setA', true); + $classDef->addMethodParameter('setA', 'a', array('type' => false, 'required' => true)); + $di->definitions()->addDefinition($classDef, false); + + $d = $di->get( + 'ZendTest\Di\TestAsset\SetterInjection\D', + array('a' => 'ZendTest\Di\TestAsset\SetterInjection\A') + ); + + $this->assertSame($d->a, 'ZendTest\Di\TestAsset\SetterInjection\A'); + } + } diff --git a/test/InstanceManagerTest.php b/test/InstanceManagerTest.php index 207f4974..82b22ebc 100644 --- a/test/InstanceManagerTest.php +++ b/test/InstanceManagerTest.php @@ -1,33 +1,41 @@ addSharedInstance($obj, 'ZendTest\Di\TestAsset\BasicClass'); $this->assertTrue($im->hasSharedInstance('ZendTest\Di\TestAsset\BasicClass')); - $this->assertSame($obj, $im->getSharedInstance('ZendTest\Di\TestAsset\BasicClass')); + $this->assertSame($obj, $im->getSharedInstance('ZendTest\Di\TestAsset\BasicClass')); } - + public function testInstanceManagerCanPersistInstancesWithParameters() { $im = new InstanceManager(); $obj1 = new TestAsset\BasicClass(); $obj2 = new TestAsset\BasicClass(); $obj3 = new TestAsset\BasicClass(); - + $im->addSharedInstance($obj1, 'foo'); $im->addSharedInstanceWithParameters($obj2, 'foo', array('foo' => 'bar')); $im->addSharedInstanceWithParameters($obj3, 'foo', array('foo' => 'baz')); - + $this->assertSame($obj1, $im->getSharedInstance('foo')); $this->assertSame($obj2, $im->getSharedInstanceWithParameters('foo', array('foo' => 'bar'))); $this->assertSame($obj3, $im->getSharedInstanceWithParameters('foo', array('foo' => 'baz'))); @@ -61,19 +69,19 @@ public function testInstanceManagerThrowsExceptionForRecursiveAliases() /** * @group AliasAlias */ - public function testInstanceManagerResolvesRecursiveAliasesForConfiguration() + public function testInstanceManagerResolvesRecursiveAliasesForConfig() { $config = array('parameters' => array('username' => 'my-username')); $im = new InstanceManager; $im->addAlias('bar-alias', 'Some\Class'); $im->addAlias('foo-alias', 'bar-alias'); - $im->setConfiguration('bar-alias', $config); + $im->setConfig('bar-alias', $config); $config['injections'] = array(); $config['shared'] = true; - - $this->assertEquals($config, $im->getConfiguration('foo-alias')); + + $this->assertEquals($config, $im->getConfig('foo-alias')); } } diff --git a/test/ServiceLocator/DependencyInjectorProxyTest.php b/test/ServiceLocator/DependencyInjectorProxyTest.php new file mode 100644 index 00000000..0ea48ce7 --- /dev/null +++ b/test/ServiceLocator/DependencyInjectorProxyTest.php @@ -0,0 +1,28 @@ +instanceManager()->setParameters( + 'ZendTest\Di\TestAsset\SetterInjection\B', + array('a' => $a) + ); + $proxy = new DependencyInjectorProxy($di); + $b = $proxy->get('ZendTest\Di\TestAsset\SetterInjection\B'); + $methods = $b->getMethods(); + $this->assertSame('setA', $methods[0]['method']); + $this->assertSame($a, $methods[0]['params'][0]); + } +} diff --git a/test/ServiceLocator/GeneratorTest.php b/test/ServiceLocator/GeneratorTest.php index 9d2c6722..173964a3 100644 --- a/test/ServiceLocator/GeneratorTest.php +++ b/test/ServiceLocator/GeneratorTest.php @@ -1,12 +1,21 @@ markTestIncomplete('Generator must be refactored to current di.'); $this->tmpFile = false; $this->di = new Di; } @@ -84,7 +92,7 @@ public function createDefinitions() )), ), ); - $configuration = new Configuration($data); + $configuration = new Config($data); $configuration->configure($this->di); } @@ -164,11 +172,11 @@ public function testCreatesContainerClassWithCasesForEachService() } $expected = array( 'composed', - 'ZendTest\Di\TestAsset\ComposedClass', + 'ZendTest\Di\TestAsset\ComposedClass', 'inspect', - 'ZendTest\Di\TestAsset\InspectedClass', + 'ZendTest\Di\TestAsset\InspectedClass', 'struct', - 'ZendTest\Di\TestAsset\Struct', + 'ZendTest\Di\TestAsset\Struct', ); $this->assertEquals(count($expected), count($services), var_export($services, 1)); foreach ($expected as $service) { @@ -206,7 +214,7 @@ public function testCreatesContainerClassWithMethodsForEachServiceAndAlias() $expected = array( 'get', 'getZendTestDiTestAssetComposedClass', - 'getComposed', + 'getComposed', 'getZendTestDiTestAssetInspectedClass', 'getInspect', 'getZendTestDiTestAssetStruct', @@ -224,7 +232,7 @@ public function testAllowsRetrievingClassFileCodeGenerationObject() $builder = new ContainerGenerator($this->di); $builder->setContainerClass('Application'); $codegen = $builder->getCodeGenerator(); - $this->assertInstanceOf('Zend\CodeGenerator\Php\PhpFile', $codegen); + $this->assertInstanceOf('Zend\Code\Generator\FileGenerator', $codegen); } public function testCanSpecifyNamespaceForGeneratedPhpClassfile() @@ -253,7 +261,7 @@ public function testNullAsOnlyArgumentResultsInEmptyParameterList() $def->addClass($opt); $this->di->setDefinition($def); - $cfg = new Configuration(array( + $cfg = new Config(array( 'instance' => array( 'alias' => array('optional' => 'ZendTest\Di\TestAsset\OptionalArg'), ), @@ -303,7 +311,7 @@ public function testNullAsLastArgumentsResultsInTruncatedParameterList() $this->di->setDefinition($def); - $cfg = new Configuration(array( + $cfg = new Config(array( 'instance' => array( 'alias' => array( 'struct' => 'ZendTest\Di\TestAsset\Struct', @@ -352,7 +360,7 @@ public function testNullArgumentsResultInEmptyMethodParameterList() $def->addClass($opt); $this->di->setDefinition($def); - $cfg = new Configuration(array( + $cfg = new Config(array( 'instance' => array( 'alias' => array('optional' => 'ZendTest\Di\TestAsset\OptionalArg'), ), diff --git a/test/ServiceLocatorTest.php b/test/ServiceLocatorTest.php index d230f2fb..c3eac273 100644 --- a/test/ServiceLocatorTest.php +++ b/test/ServiceLocatorTest.php @@ -1,8 +1,17 @@ test = $test; diff --git a/test/TestAsset/InheritanceClasses/B.php b/test/TestAsset/InheritanceClasses/B.php index 017d04d8..aeb3f426 100644 --- a/test/TestAsset/InheritanceClasses/B.php +++ b/test/TestAsset/InheritanceClasses/B.php @@ -1,4 +1,12 @@ foo = $foo; + } +} diff --git a/test/TestAsset/OptionalArg.php b/test/TestAsset/OptionalArg.php index c3eb0dde..db011d30 100644 --- a/test/TestAsset/OptionalArg.php +++ b/test/TestAsset/OptionalArg.php @@ -1,4 +1,13 @@ a = $a; + } +} diff --git a/test/TestAsset/SetterInjection/X.php b/test/TestAsset/SetterInjection/X.php index 0d0aa816..55f0f48d 100644 --- a/test/TestAsset/SetterInjection/X.php +++ b/test/TestAsset/SetterInjection/X.php @@ -1,4 +1,12 @@ + 'My\\DbAdapter' => array ( - 'superTypes' => + 'superTypes' => array ( ), 'instantiator' => '__construct', 'methods' => array ( - '__construct' => + '__construct' => array ( 'username' => NULL, 'password' => NULL, ), ), ), - 'My\\EntityA' => + 'My\\EntityA' => array ( 'supertypes' => array ( @@ -24,7 +24,7 @@ array ( ), ), - 'My\\Mapper' => + 'My\\Mapper' => array ( 'supertypes' => array ( @@ -33,27 +33,27 @@ 'instantiator' => '__construct', 'methods' => array ( - 'setDbAdapter' => + 'setDbAdapter' => array ( 'dbAdapter' => 'My\\DbAdapter', ), ), ), - 'My\\RepositoryA' => + 'My\\RepositoryA' => array ( 'superTypes' => array ( ), 'instantiator' => '__construct', - 'injectionMethods' => + 'injectionMethods' => array ( - 'setMapper' => + 'setMapper' => array ( 'mapper' => 'My\\Mapper', ), ), ), - 'My\\RepositoryB' => + 'My\\RepositoryB' => array ( 'superTypes' => array ( diff --git a/test/_files/sample.php b/test/_files/sample.php index 5f6e79e6..a670f604 100644 --- a/test/_files/sample.php +++ b/test/_files/sample.php @@ -7,4 +7,4 @@ ), ), ), -); \ No newline at end of file +);