|
2 | 2 |
|
3 | 3 | namespace Illuminate\Tests\Routing;
|
4 | 4 |
|
| 5 | +use Attribute; |
5 | 6 | use Closure;
|
6 | 7 | use DateTime;
|
7 | 8 | use Exception;
|
8 | 9 | use Illuminate\Auth\Middleware\Authenticate;
|
9 | 10 | use Illuminate\Auth\Middleware\Authorize;
|
| 11 | +use Illuminate\Config\Repository; |
| 12 | +use Illuminate\Container\Attributes\Config; |
10 | 13 | use Illuminate\Container\Container;
|
11 | 14 | use Illuminate\Contracts\Routing\Registrar;
|
12 | 15 | use Illuminate\Contracts\Support\Responsable;
|
@@ -1107,6 +1110,48 @@ public function testModelBindingThroughIOC()
|
1107 | 1110 | $this->assertSame('TAYLOR', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent());
|
1108 | 1111 | }
|
1109 | 1112 |
|
| 1113 | + public function testRouteDependenciesCanBeResolvedThroughAttributes() |
| 1114 | + { |
| 1115 | + $container = new Container; |
| 1116 | + $container->singleton('config', fn () => new Repository([ |
| 1117 | + 'app' => [ |
| 1118 | + 'timezone' => 'Europe/Paris', |
| 1119 | + ], |
| 1120 | + ])); |
| 1121 | + $router = new Router(new Dispatcher, $container); |
| 1122 | + $container->instance(Registrar::class, $router); |
| 1123 | + $container->bind(CallableDispatcherContract::class, fn ($app) => new CallableDispatcher($app)); |
| 1124 | + $router->get('foo', [ |
| 1125 | + 'middleware' => SubstituteBindings::class, |
| 1126 | + 'uses' => function (#[Config('app.timezone')] string $value) { |
| 1127 | + return $value; |
| 1128 | + }, |
| 1129 | + ]); |
| 1130 | + |
| 1131 | + $this->assertSame('Europe/Paris', $router->dispatch(Request::create('foo', 'GET'))->getContent()); |
| 1132 | + } |
| 1133 | + |
| 1134 | + public function testAfterResolvingAttributeCallbackIsCalledOnRouteDependenciesResolution() |
| 1135 | + { |
| 1136 | + $container = new Container(); |
| 1137 | + $router = new Router(new Dispatcher, $container); |
| 1138 | + $container->instance(Registrar::class, $router); |
| 1139 | + $container->bind(CallableDispatcherContract::class, fn ($app) => new CallableDispatcher($app)); |
| 1140 | + |
| 1141 | + $container->afterResolvingAttribute(RoutingTestOnTenant::class, function (RoutingTestOnTenant $attribute, RoutingTestHasTenantImpl $hasTenantImpl, Container $container) { |
| 1142 | + $hasTenantImpl->onTenant($attribute->tenant); |
| 1143 | + }); |
| 1144 | + |
| 1145 | + $router->get('foo', [ |
| 1146 | + 'middleware' => SubstituteBindings::class, |
| 1147 | + 'uses' => function (#[RoutingTestOnTenant(RoutingTestTenant::TenantA)] RoutingTestHasTenantImpl $property) { |
| 1148 | + return $property->tenant->name; |
| 1149 | + }, |
| 1150 | + ]); |
| 1151 | + |
| 1152 | + $this->assertSame('TenantA', $router->dispatch(Request::create('foo', 'GET'))->getContent()); |
| 1153 | + } |
| 1154 | + |
1110 | 1155 | public function testGroupMerging()
|
1111 | 1156 | {
|
1112 | 1157 | $old = ['prefix' => 'foo/bar/'];
|
@@ -2639,3 +2684,28 @@ public function handle($request, Closure $next)
|
2639 | 2684 | return $next($request);
|
2640 | 2685 | }
|
2641 | 2686 | }
|
| 2687 | + |
| 2688 | +#[Attribute(Attribute::TARGET_PARAMETER)] |
| 2689 | +final class RoutingTestOnTenant |
| 2690 | +{ |
| 2691 | + public function __construct( |
| 2692 | + public readonly RoutingTestTenant $tenant |
| 2693 | + ) { |
| 2694 | + } |
| 2695 | +} |
| 2696 | + |
| 2697 | +enum RoutingTestTenant |
| 2698 | +{ |
| 2699 | + case TenantA; |
| 2700 | + case TenantB; |
| 2701 | +} |
| 2702 | + |
| 2703 | +final class RoutingTestHasTenantImpl |
| 2704 | +{ |
| 2705 | + public ?RoutingTestTenant $tenant = null; |
| 2706 | + |
| 2707 | + public function onTenant(RoutingTestTenant $tenant): void |
| 2708 | + { |
| 2709 | + $this->tenant = $tenant; |
| 2710 | + } |
| 2711 | +} |
0 commit comments