From 440ffebb3efbeffd71ac1ed8dde0fa9b546a4626 Mon Sep 17 00:00:00 2001 From: Jamie Thorpe Date: Tue, 22 Oct 2024 23:53:27 -0400 Subject: [PATCH] fix: allows injection using multiple interfaces with the same concrete implementation --- .../Routing/ResolvesRouteDependencies.php | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Routing/ResolvesRouteDependencies.php b/src/Illuminate/Routing/ResolvesRouteDependencies.php index 9bd32a89a965..3971385a1edd 100644 --- a/src/Illuminate/Routing/ResolvesRouteDependencies.php +++ b/src/Illuminate/Routing/ResolvesRouteDependencies.php @@ -47,15 +47,30 @@ public function resolveMethodDependencies(array $parameters, ReflectionFunctionA $skippableValue = new stdClass; + $resolvedInterfaces = []; + foreach ($reflector->getParameters() as $key => $parameter) { - $instance = $this->transformDependency($parameter, $parameters, $skippableValue); + $className = Reflector::getParameterClassName($parameter); + + // If the parameter has a type-hinted class, we will check to see if it is already in + // the list of parameters. If it is we will just skip it as it is probably a model + // binding and we do not want to mess with those; otherwise, we resolve it here. + if ($className && (! $this->alreadyInParameters($className, $parameters) || ! $this->alreadyInResolvedInterfaces($className, $resolvedInterfaces))) { + $instance = $this->transformDependency($parameter, $className); + + if (interface_exists($className) && !class_exists($className) && $instance !== $skippableValue) { + $resolvedInterfaces[] = $className; + } + } else { + $instance = $skippableValue; + } if ($instance !== $skippableValue) { $instanceCount++; $this->spliceIntoParameters($parameters, $key, $instance); } elseif (! isset($values[$key - $instanceCount]) && - $parameter->isDefaultValueAvailable()) { + $parameter->isDefaultValueAvailable()) { $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue()); } @@ -73,26 +88,17 @@ public function resolveMethodDependencies(array $parameters, ReflectionFunctionA * @param object $skippableValue * @return mixed */ - protected function transformDependency(ReflectionParameter $parameter, $parameters, $skippableValue) + protected function transformDependency(ReflectionParameter $parameter, $className) { - $className = Reflector::getParameterClassName($parameter); - if ($attribute = Util::getContextualAttributeFromDependency($parameter)) { return $this->container->resolveFromAttribute($attribute); } - // If the parameter has a type-hinted class, we will check to see if it is already in - // the list of parameters. If it is we will just skip it as it is probably a model - // binding and we do not want to mess with those; otherwise, we resolve it here. - if ($className && ! $this->alreadyInParameters($className, $parameters)) { - $isEnum = (new ReflectionClass($className))->isEnum(); - - return $parameter->isDefaultValueAvailable() - ? ($isEnum ? $parameter->getDefaultValue() : null) - : $this->container->make($className); - } + $isEnum = (new ReflectionClass($className))->isEnum(); - return $skippableValue; + return $parameter->isDefaultValueAvailable() + ? ($isEnum ? $parameter->getDefaultValue() : null) + : $this->container->make($className); } /** @@ -107,6 +113,11 @@ protected function alreadyInParameters($class, array $parameters) return ! is_null(Arr::first($parameters, fn ($value) => $value instanceof $class)); } + protected function alreadyInResolvedInterfaces($class, array $resolvedInterfaces) + { + return in_array($class, $resolvedInterfaces); + } + /** * Splice the given value into the parameter list. *