From 6789f3c73143554d5c2b13a7fb82bb65677a2cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alfaiate?= Date: Tue, 17 Jun 2025 10:25:04 +0700 Subject: [PATCH] [12.x] fix method dependencies order --- .../Routing/ResolvesRouteDependencies.php | 32 +++++++++++-------- tests/Routing/RoutingRouteTest.php | 10 +++--- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Routing/ResolvesRouteDependencies.php b/src/Illuminate/Routing/ResolvesRouteDependencies.php index bd3139fc7691..a0d15cde04bc 100644 --- a/src/Illuminate/Routing/ResolvesRouteDependencies.php +++ b/src/Illuminate/Routing/ResolvesRouteDependencies.php @@ -41,22 +41,23 @@ protected function resolveClassMethodDependencies(array $parameters, $instance, */ public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector) { - $instanceCount = 0; - + $keys = array_keys($parameters); $values = array_values($parameters); $skippableValue = new stdClass; foreach ($reflector->getParameters() as $key => $parameter) { - $instance = $this->transformDependency($parameter, $parameters, $skippableValue); - - if ($instance !== $skippableValue) { - $instanceCount++; - + if (false !== ($position = array_search($parameter->name, $keys, true))) { + $instance = $parameters[$parameter->name]; + unset($keys[$position], $values[$position], $parameters[$parameter->name]); + $this->spliceIntoParameters($parameters, $key, $instance, $parameter->name); + } elseif ($skippableValue !== ($instance = $this->transformDependency($parameter, $values, $skippableValue))) { $this->spliceIntoParameters($parameters, $key, $instance); - } elseif (! isset($values[$key - $instanceCount]) && - $parameter->isDefaultValueAvailable()) { + } elseif (empty($values) && $parameter->isDefaultValueAvailable()) { $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue()); + } else { + array_shift($keys); + array_shift($values); } $this->container->fireAfterResolvingAttributeCallbacks($parameter->getAttributes(), $instance); @@ -113,12 +114,17 @@ protected function alreadyInParameters($class, array $parameters) * @param array $parameters * @param string $offset * @param mixed $value + * @param string|null $key * @return void */ - protected function spliceIntoParameters(array &$parameters, $offset, $value) + protected function spliceIntoParameters(array &$parameters, $offset, $value, ?string $key = null) { - array_splice( - $parameters, $offset, 0, [$value] - ); + if (null === $key) { + array_splice($parameters, $offset, 0, [$value]); + } else { + $parameters = array_slice($parameters, 0, $offset, true) + + [$key => $value] + + array_slice($parameters, $offset, null, true); + } } } diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index c44c2fd69a80..2720bbec2eba 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -684,31 +684,31 @@ public function testControllerCallActionMethodParameters() unset($_SERVER['__test.controller_callAction_parameters']); $router->get(($str = Str::random()).'/{one}/{two}', RouteTestAnotherControllerWithParameterStub::class.'@oneArgument'); $router->dispatch(Request::create($str.'/one/two', 'GET')); - $this->assertEquals(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); + $this->assertSame(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); // Has two arguments and receives two unset($_SERVER['__test.controller_callAction_parameters']); $router->get(($str = Str::random()).'/{one}/{two}', RouteTestAnotherControllerWithParameterStub::class.'@twoArguments'); $router->dispatch(Request::create($str.'/one/two', 'GET')); - $this->assertEquals(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); + $this->assertSame(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); // Has two arguments but with different names from the ones passed from the route unset($_SERVER['__test.controller_callAction_parameters']); $router->get(($str = Str::random()).'/{one}/{two}', RouteTestAnotherControllerWithParameterStub::class.'@differentArgumentNames'); $router->dispatch(Request::create($str.'/one/two', 'GET')); - $this->assertEquals(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); + $this->assertSame(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); // Has two arguments with same name but argument order is reversed unset($_SERVER['__test.controller_callAction_parameters']); $router->get(($str = Str::random()).'/{one}/{two}', RouteTestAnotherControllerWithParameterStub::class.'@reversedArguments'); $router->dispatch(Request::create($str.'/one/two', 'GET')); - $this->assertEquals(['one' => 'one', 'two' => 'two'], $_SERVER['__test.controller_callAction_parameters']); + $this->assertSame(['two' => 'two', 'one' => 'one'], $_SERVER['__test.controller_callAction_parameters']); // No route parameters while method has parameters unset($_SERVER['__test.controller_callAction_parameters']); $router->get(($str = Str::random()).'', RouteTestAnotherControllerWithParameterStub::class.'@oneArgument'); $router->dispatch(Request::create($str, 'GET')); - $this->assertEquals([], $_SERVER['__test.controller_callAction_parameters']); + $this->assertSame([], $_SERVER['__test.controller_callAction_parameters']); // With model bindings unset($_SERVER['__test.controller_callAction_parameters']);