diff --git a/Compiler/ClassConstructorFiller.php b/Compiler/ClassConstructorFiller.php index 4ead5a8..ae66a28 100644 --- a/Compiler/ClassConstructorFiller.php +++ b/Compiler/ClassConstructorFiller.php @@ -26,7 +26,7 @@ public function autowireParams(ReflectionMethod $constructor, $serviceId, Defini } else if ($parameter->isDefaultValueAvailable()) { $allArguments[] = $parameter->getDefaultValue(); } else { - $allArguments[] = $this->parameterProcessor->getParameterValue($parameter, $classes, $serviceId); + $allArguments[] = $this->parameterProcessor->getParameterValue($constructor, $classes, $serviceId, $parameter); } } diff --git a/Compiler/ParameterProcessor.php b/Compiler/ParameterProcessor.php index 7c1ebfd..e65f289 100644 --- a/Compiler/ParameterProcessor.php +++ b/Compiler/ParameterProcessor.php @@ -3,43 +3,114 @@ namespace Kutny\AutowiringBundle\Compiler; use ReflectionClass; +use ReflectionMethod; use ReflectionParameter; use Symfony\Component\DependencyInjection\Reference; class ParameterProcessor { - public function getParameterValue(ReflectionParameter $parameter, array $classes, $serviceId) + public function getParameterValue(ReflectionMethod $method, array $classes, $serviceId, ReflectionParameter $parameter) { - $parameterClass = $parameter->getClass(); + $value = null; + $resolved = false; - if ($parameterClass) { + // resolve by type hint + if (!$resolved && ($parameterClass = $parameter->getClass())) { $value = $this->processParameterClass($parameterClass, $parameter, $classes); - } else { - if ($parameter->isDefaultValueAvailable()) { - $value = $parameter->getDefaultValue(); - } else { - $message = 'Class ' . $parameter->getDeclaringClass()->getName() . ' (service: ' . $serviceId . '), parameter $' . $parameter->getName(); + $resolved = true; + } + + // resolve array by doc comment @param type + if (!$resolved && $parameter->isArray()) { + if ($docComment = $method->getDocComment()) { + $paramAnnotationExists = preg_match( + "/@param\\s+(?[A-Za-z0-9_]+)\\[\\]\\s+\\\${$parameter->getName()}/", + $docComment, + $paramAnnotation + ); - throw new CannotResolveParameterException($message); + if ($paramAnnotationExists) { + $uses = $this->extractUses($method->getDeclaringClass()); + $parameterClass = $paramAnnotation["type"]; + if ($parameterClass[0] !== "\\") { + if (isset($uses[$parameterClass])) { + $parameterClass = $uses[$parameterClass]; + } else { + $parameterClass = $method->getDeclaringClass()->getNamespaceName() . "\\" . $parameterClass; + } + } + + $parameterClass = trim($parameterClass, "\\"); + + $value = $this->processParameterClass(new ReflectionClass($parameterClass), $parameter, $classes, true); + $resolved = true; + } } } + // try default value + if (!$resolved && $parameter->isDefaultValueAvailable()) { + $value = $parameter->getDefaultValue(); + $resolved = true; + } + + // exception if not resolved + if (!$resolved) { + throw new CannotResolveParameterException( + 'Class ' . $parameter->getDeclaringClass()->getName() . + ' (service: ' . $serviceId . '), ' . + 'parameter $' . $parameter->getName() + ); + } + return $value; } - private function processParameterClass(ReflectionClass $parameterClass, ReflectionParameter $parameter, $classes) + private function extractUses(ReflectionClass $class) + { + $fileContents = file_get_contents($class->getFileName()); + $uses = array(); + + if (preg_match_all( + "/\\b[uU][sS][eE]\\s+((?[A-Za-z0-9_\\\\]+)(?:\\s+[aA][sS]\\s+(?[A-Za-z0-9_\\\\]+))?)\\s*;/", + $fileContents, $matches) + ) { + for ($i = 0, $l = count($matches["fqn"]); $i < $l; ++$i) { + list($fqn, $alias) = array($matches["fqn"][$i], $matches["alias"][$i]); + + if (empty($alias)) { + $classPath = explode("\\", $fqn); + $alias = array_pop($classPath); + } + + $uses[$alias] = $fqn; + } + } + + return $uses; + } + + private function processParameterClass(ReflectionClass $parameterClass, ReflectionParameter $parameter, $classes, $arrayOfServices = false) { $class = $parameterClass->getName(); if (isset($classes[$class])) { - if (count($classes[$class]) === 1) { - $value = new Reference($classes[$class][0]); + if ($arrayOfServices) { + $value = array_map(function ($serviceId) { + return new Reference($serviceId); + }, $classes[$class]); + } else { - $serviceNames = implode(', ', $classes[$class]); - $message = 'Multiple services of ' . $class . ' defined (' . $serviceNames . '), class used in ' . $parameter->getDeclaringClass()->getName(); + if (count($classes[$class]) === 1) { + $value = new Reference($classes[$class][0]); + + } else { + $serviceNames = implode(', ', $classes[$class]); + $message = 'Multiple services of ' . $class . ' defined (' . $serviceNames . '), class used in ' . $parameter->getDeclaringClass()->getName(); - throw new MultipleServicesOfClassException($message); + throw new MultipleServicesOfClassException($message); + } } } else { if ($parameter->isDefaultValueAvailable()) {