Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / dependency-injection / Compiler / AutowirePass.php
index b2795485531615ff281e0fa7479a4bb5a86e7360..ae1f24d31780559b59426bf029d7490411556b90 100644 (file)
@@ -11,6 +11,7 @@
 
 namespace Symfony\Component\DependencyInjection\Compiler;
 
+use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Definition;
 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -27,7 +28,7 @@ class AutowirePass implements CompilerPassInterface
     private $reflectionClasses = array();
     private $definedTypes = array();
     private $types;
-    private $notGuessableTypes = array();
+    private $ambiguousServiceTypes = array();
     private $autowired = array();
 
     /**
@@ -45,23 +46,38 @@ class AutowirePass implements CompilerPassInterface
                     $this->completeDefinition($id, $definition);
                 }
             }
-        } catch (\Exception $e) {
-        } catch (\Throwable $e) {
+        } finally {
+            spl_autoload_unregister($throwingAutoloader);
+
+            // Free memory and remove circular reference to container
+            $this->reflectionClasses = array();
+            $this->definedTypes = array();
+            $this->types = null;
+            $this->ambiguousServiceTypes = array();
+            $this->autowired = array();
         }
+    }
 
-        spl_autoload_unregister($throwingAutoloader);
+    /**
+     * Creates a resource to help know if this service has changed.
+     *
+     * @param \ReflectionClass $reflectionClass
+     *
+     * @return AutowireServiceResource
+     */
+    public static function createResourceForClass(\ReflectionClass $reflectionClass)
+    {
+        $metadata = array();
 
-        // Free memory and remove circular reference to container
-        $this->container = null;
-        $this->reflectionClasses = array();
-        $this->definedTypes = array();
-        $this->types = null;
-        $this->notGuessableTypes = array();
-        $this->autowired = array();
+        if ($constructor = $reflectionClass->getConstructor()) {
+            $metadata['__construct'] = self::getResourceMetadataForMethod($constructor);
+        }
 
-        if (isset($e)) {
-            throw $e;
+        foreach (self::getSetters($reflectionClass) as $reflectionMethod) {
+            $metadata[$reflectionMethod->name] = self::getResourceMetadataForMethod($reflectionMethod);
         }
+
+        return new AutowireServiceResource($reflectionClass->name, $reflectionClass->getFileName(), $metadata);
     }
 
     /**
@@ -74,7 +90,7 @@ class AutowirePass implements CompilerPassInterface
      */
     private function completeDefinition($id, Definition $definition)
     {
-        if ($definition->getFactory() || $definition->getFactoryClass(false) || $definition->getFactoryService(false)) {
+        if ($definition->getFactory()) {
             throw new RuntimeException(sprintf('Service "%s" can use either autowiring or a factory, not both.', $id));
         }
 
@@ -82,7 +98,9 @@ class AutowirePass implements CompilerPassInterface
             return;
         }
 
-        $this->container->addClassResource($reflectionClass);
+        if ($this->container->isTrackingResources()) {
+            $this->container->addResource(static::createResourceForClass($reflectionClass));
+        }
 
         if (!$constructor = $reflectionClass->getConstructor()) {
             return;
@@ -124,7 +142,7 @@ class AutowirePass implements CompilerPassInterface
                     $this->populateAvailableTypes();
                 }
 
-                if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) {
+                if (isset($this->types[$typeHint->name])) {
                     $value = new Reference($this->types[$typeHint->name]);
                 } else {
                     try {
@@ -197,7 +215,7 @@ class AutowirePass implements CompilerPassInterface
         foreach ($definition->getAutowiringTypes() as $type) {
             $this->definedTypes[$type] = true;
             $this->types[$type] = $id;
-            unset($this->notGuessableTypes[$type]);
+            unset($this->ambiguousServiceTypes[$type]);
         }
 
         if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
@@ -225,22 +243,26 @@ class AutowirePass implements CompilerPassInterface
             return;
         }
 
-        if (!isset($this->types[$type])) {
-            $this->types[$type] = $id;
+        // is this already a type/class that is known to match multiple services?
+        if (isset($this->ambiguousServiceTypes[$type])) {
+            $this->ambiguousServiceTypes[$type][] = $id;
 
             return;
         }
 
-        if ($this->types[$type] === $id) {
+        // check to make sure the type doesn't match multiple services
+        if (!isset($this->types[$type]) || $this->types[$type] === $id) {
+            $this->types[$type] = $id;
+
             return;
         }
 
-        if (!isset($this->notGuessableTypes[$type])) {
-            $this->notGuessableTypes[$type] = true;
-            $this->types[$type] = (array) $this->types[$type];
+        // keep an array of all services matching this type
+        if (!isset($this->ambiguousServiceTypes[$type])) {
+            $this->ambiguousServiceTypes[$type] = array($this->types[$type]);
+            unset($this->types[$type]);
         }
-
-        $this->types[$type][] = $id;
+        $this->ambiguousServiceTypes[$type][] = $id;
     }
 
     /**
@@ -255,9 +277,9 @@ class AutowirePass implements CompilerPassInterface
      */
     private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
     {
-        if (isset($this->notGuessableTypes[$typeHint->name])) {
+        if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
             $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
-            $matchingServices = implode(', ', $this->types[$typeHint->name]);
+            $matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);
 
             throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
         }
@@ -331,4 +353,40 @@ class AutowirePass implements CompilerPassInterface
 
         return $this->reflectionClasses[$id] = $reflector;
     }
+
+    /**
+     * @param \ReflectionClass $reflectionClass
+     *
+     * @return \ReflectionMethod[]
+     */
+    private static function getSetters(\ReflectionClass $reflectionClass)
+    {
+        foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
+            if (!$reflectionMethod->isStatic() && 1 === $reflectionMethod->getNumberOfParameters() && 0 === strpos($reflectionMethod->name, 'set')) {
+                yield $reflectionMethod;
+            }
+        }
+    }
+
+    private static function getResourceMetadataForMethod(\ReflectionMethod $method)
+    {
+        $methodArgumentsMetadata = array();
+        foreach ($method->getParameters() as $parameter) {
+            try {
+                $class = $parameter->getClass();
+            } catch (\ReflectionException $e) {
+                // type-hint is against a non-existent class
+                $class = false;
+            }
+
+            $isVariadic = method_exists($parameter, 'isVariadic') && $parameter->isVariadic();
+            $methodArgumentsMetadata[] = array(
+                'class' => $class,
+                'isOptional' => $parameter->isOptional(),
+                'defaultValue' => ($parameter->isOptional() && !$isVariadic) ? $parameter->getDefaultValue() : null,
+            );
+        }
+
+        return $methodArgumentsMetadata;
+    }
 }