public function process(ContainerBuilder $container) { $parameterBag = $container->getParameterBag(); foreach ($container->getDefinitions() as $serviceId => $definition) { if (!$this->canBeAdded($definition)) { continue; } $this->classMap->put($parameterBag->resolveValue($definition->getClass()), $serviceId); } }
/** * @param ReflectionClass $reflectionClass * @param string $docComment * @param string $parameterName * @param ReflectionClass $parameterReflectionClass * @param mixed $defaultValueAvailable * @param mixed $defaultValue * @param $preferredServices * @return mixed */ private function getValue(ReflectionClass $reflectionClass, $docComment, $parameterName, ReflectionClass $parameterReflectionClass = null, $defaultValueAvailable, $defaultValue, $preferredServices) { $className = null; $isArray = false; // resolve class name, whether value is array if ($parameterName !== null) { // parse parameter class if ($parameterReflectionClass) { $className = $parameterReflectionClass->getName(); } elseif (preg_match("/@param\\s+([a-zA-Z0-9\\\\_]+)(\\[\\])?(\\|[^\\s]+)*\\s+\\\$" . preg_quote($parameterName) . "/", $docComment, $m)) { $className = $m[1]; $isArray = isset($m[2]) && $m[2] === "[]"; } elseif (!$defaultValueAvailable) { throw new AutowiringException("Could not parse parameter type - neither type hint, nor @param annotation available."); } } else { // parse property class if (preg_match("/@var\\s+([a-zA-Z0-9\\\\_]+)(\\[\\])?/", $docComment, $m)) { $className = $m[1]; $isArray = isset($m[2]) && $m[2] === "[]"; } elseif (!$defaultValueAvailable) { throw new AutowiringException("Could not parse property type - no @var annotation."); } } // resolve class name to FQN $lowerClassName = trim(strtolower($className), "\\ \t\n"); $useStatements = $this->getUseStatements($reflectionClass); if (isset($useStatements[$lowerClassName])) { $className = $useStatements[$lowerClassName]; } elseif (strpos($className, "\\") === false) { $className = $reflectionClass->getNamespaceName() . "\\" . $className; } $className = trim($className, "\\"); // autowire from class map if ($isArray) { return array_map(function ($serviceId) { return new Reference($serviceId); }, $this->classMap->getMulti($className)); } elseif ($className !== null) { try { return new Reference($this->classMap->getSingle($className)); } catch (NoValueException $exception) { if ($defaultValueAvailable) { return $defaultValue; } else { throw new AutowiringException(sprintf("Missing service of type '%s'.", $className)); } } catch (MultipleValuesException $exception) { if (isset($preferredServices[$className])) { return new Reference($preferredServices[$className]); } else { throw new AutowiringException(sprintf("Multiple services of type '%s'.", $className)); } } } elseif ($defaultValueAvailable) { return $defaultValue; } else { throw new AutowiringException("Could not autowire."); } }
public function process(ContainerBuilder $container) { $parameterBag = $container->getParameterBag(); try { $autoscanPsr4 = (array) $parameterBag->resolveValue("%autowiring.autoscan_psr4%"); } catch (ParameterNotFoundException $e) { $autoscanPsr4 = []; } try { $fastAnnotationChecksRegex = implode("|", array_map(function ($s) { return preg_quote($s); }, (array) $parameterBag->resolveValue("%autowiring.fast_annotation_checks%"))); } catch (ParameterNotFoundException $e) { $fastAnnotationChecksRegex = null; } $env = $parameterBag->resolveValue("%kernel.environment%"); // TODO: better error state handling if (empty($autoscanPsr4) || empty($fastAnnotationChecksRegex)) { return; } // TODO: more find methods than grep $grep = "egrep -lir " . escapeshellarg($fastAnnotationChecksRegex); foreach ($autoscanPsr4 as $ns => $dir) { if (!is_dir($dir)) { throw new AutowiringException(sprintf("Autoscan directory '%s' does not exits.", $dir)); } $autoscanPsr4[$ns] = $dir = realpath($dir); $grep .= " " . escapeshellarg($dir); } if (($files = shell_exec($grep)) === null) { throw new AutowiringException("Autoscan grep failed."); } $classNames = []; foreach (explode("\n", trim($files)) as $file) { if (substr($file, -4) !== ".php") { continue; } foreach ($autoscanPsr4 as $ns => $dir) { if (strncmp($file, $dir, strlen($dir)) === 0) { $fileWithoutDir = substr($file, strlen($dir), strlen($file) - strlen($dir) - 4); $className = $ns . str_replace("/", "\\", $fileWithoutDir); $classNames[$className] = $file; break; } } } foreach ($classNames as $className => $file) { $serviceIds = $this->classMap->getMulti($className); if (!empty($serviceIds)) { continue; } try { $rc = new \ReflectionClass($className); } catch (\ReflectionException $e) { throw new AutowiringException(sprintf("File '%s' does not contain class '%s', or class is not autoload-able. " . "Check 'autowiring.autoscan_psr4' configuration if you specified the path correctly.", $file, $className)); } $annotations = $this->annotationReader->getClassAnnotations($rc); foreach ($annotations as $annotation) { if ($annotation instanceof Component && ($annotation->env === $env || $annotation->env === null)) { $serviceId = $annotation->name; if ($serviceId === null) { $annotationClassName = get_class($annotation); $annotationSimpleName = substr($annotationClassName, strrpos($annotationClassName, "\\") + 1); $classNameParts = explode("\\", $className); $classSimpleName = array_pop($classNameParts); $annotationLen = strlen($annotationSimpleName); if (substr($classSimpleName, -$annotationLen) === $annotationSimpleName) { $classSimpleName = substr($classSimpleName, 0, strlen($classSimpleName) - $annotationLen); } $middle = "."; do { $serviceId = lcfirst($annotationSimpleName) . $middle . lcfirst($classSimpleName); do { $part = array_pop($classNameParts); } while ($part === $annotationSimpleName && !empty($classNameParts)); $middle = "." . lcfirst($part) . $middle; } while ($container->hasDefinition($serviceId) && !empty($classNameParts)); } if ($container->hasDefinition($serviceId)) { throw new AutowiringException(sprintf("Class '%s' cannot be added as service '%s', service ID already exists.", $className, $serviceId)); } $container->setDefinition($serviceId, new Definition($className)); } } } }
public function testGetMultiForClassAddedTwice() { $this->classMultiMap->put(self::SOME_CLASS_NAME, "someValue"); $this->classMultiMap->put(self::SOME_CLASS_NAME, "someOtherValue"); $this->assertSame(["someValue", "someOtherValue"], $this->classMultiMap->getMulti(self::SOME_CLASS_NAME)); }