mirror of
https://github.com/filamentphp/filament.git
synced 2026-08-31 01:14:50 +08:00
Fix dashboard route overwritten by home redirect when using tenant slug attribute (#19584)
* Fix dashboard route overwritten by home redirect when using tenant slug attribute
`Route::getLastGroupPrefix()` returns the raw group prefix including
binding syntax (e.g. `admin/{tenant:slug}`), but Laravel's
`RouteCollection` indexes routes by the normalized URI without binding
syntax (e.g. `admin/{tenant}`). The `isset()` check on line 182 fails
due to this key mismatch when a tenant slug attribute is configured,
causing the home redirect to be created at `/` and overwrite the
Dashboard route.
The fix strips binding syntax from the root URI before looking it up
in the route collection.
Fixes filamentphp/filament#19582
* update snapshots
---------
Co-authored-by: Dan Harrin <git@danharrin.com>
This commit is contained in:
@@ -175,7 +175,7 @@ Route::name('filament.')
|
||||
Filament::setCurrentResourceConfigurationKey(null);
|
||||
}
|
||||
|
||||
$rootUri = trim(Route::getLastGroupPrefix(), '/') ?: '/';
|
||||
$rootUri = preg_replace('/\{(\w+):\w+\}/', '{$1}', trim(Route::getLastGroupPrefix(), '/')) ?: '/';
|
||||
$groupStack = Route::getGroupStack();
|
||||
$rootKey = (end($groupStack)['domain'] ?? '') . $rootUri;
|
||||
|
||||
|
||||
+3
@@ -26,6 +26,7 @@ class ManageUserTeams extends ManageRelatedRecords
|
||||
->components([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->required(),
|
||||
Forms\Components\TextInput::make('slug'),
|
||||
Forms\Components\Textarea::make('description')
|
||||
->columnSpanFull(),
|
||||
Forms\Components\TextInput::make('budget')
|
||||
@@ -44,6 +45,8 @@ class ManageUserTeams extends ManageRelatedRecords
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('slug')
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('budget')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
||||
+3
@@ -19,6 +19,7 @@ class TeamsRelationManager extends RelationManager
|
||||
->components([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->required(),
|
||||
Forms\Components\TextInput::make('slug'),
|
||||
Forms\Components\Textarea::make('description')
|
||||
->columnSpanFull(),
|
||||
Forms\Components\TextInput::make('budget')
|
||||
@@ -37,6 +38,8 @@ class TeamsRelationManager extends RelationManager
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('slug')
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('budget')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
||||
+3
@@ -35,6 +35,7 @@ class ManageUserTeams extends ManageRelatedRecords
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->required(),
|
||||
TextInput::make('slug'),
|
||||
Textarea::make('description')
|
||||
->columnSpanFull(),
|
||||
TextInput::make('budget')
|
||||
@@ -53,6 +54,8 @@ class ManageUserTeams extends ManageRelatedRecords
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable(),
|
||||
TextColumn::make('slug')
|
||||
->searchable(),
|
||||
TextColumn::make('budget')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
||||
+3
@@ -28,6 +28,7 @@ class TeamsRelationManager extends RelationManager
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->required(),
|
||||
TextInput::make('slug'),
|
||||
Textarea::make('description')
|
||||
->columnSpanFull(),
|
||||
TextInput::make('budget')
|
||||
@@ -46,6 +47,8 @@ class TeamsRelationManager extends RelationManager
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable(),
|
||||
TextColumn::make('slug')
|
||||
->searchable(),
|
||||
TextColumn::make('budget')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
||||
@@ -13,6 +13,7 @@ class TeamFactory extends Factory
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->company(),
|
||||
'slug' => $this->faker->unique()->slug(),
|
||||
'description' => $this->faker->sentence(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ return new class extends Migration
|
||||
Schema::create('teams', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('slug')->unique()->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->decimal('budget', 10, 2)->default(0);
|
||||
$table->foreignId('company_id')->nullable();
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tests\Fixtures\Providers;
|
||||
|
||||
use Filament\Http\Middleware\Authenticate;
|
||||
use Filament\Http\Middleware\AuthenticateSession;
|
||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||
use Filament\Http\Middleware\IdentifyTenant;
|
||||
use Filament\Pages;
|
||||
use Filament\Panel;
|
||||
use Filament\PanelProvider;
|
||||
use Filament\Tests\Fixtures\Models\Team;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
|
||||
class SlugTenancyPanelProvider extends PanelProvider
|
||||
{
|
||||
public function panel(Panel $panel): Panel
|
||||
{
|
||||
return $panel
|
||||
->id('slug-tenancy')
|
||||
->path('slug-tenancy')
|
||||
->tenant(Team::class, 'slug')
|
||||
->login()
|
||||
->pages([
|
||||
Pages\Dashboard::class,
|
||||
])
|
||||
->middleware([
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
AuthenticateSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
class_exists(PreventRequestForgery::class) ? PreventRequestForgery::class : VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
DisableBladeIconComponents::class,
|
||||
DispatchServingFilamentEvent::class,
|
||||
IdentifyTenant::class,
|
||||
])
|
||||
->authMiddleware([
|
||||
Authenticate::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Filament\Tests\Panels\Pages\TestCase;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('registers the dashboard route when using a tenant slug attribute', function (): void {
|
||||
$route = Route::getRoutes()->getByName('filament.slug-tenancy.pages.dashboard');
|
||||
|
||||
expect($route)->not->toBeNull()
|
||||
->and($route->uri())->toBe('slug-tenancy/{tenant}');
|
||||
});
|
||||
|
||||
it('does not register the home redirect when the dashboard occupies the root path with a tenant slug attribute', function (): void {
|
||||
expect(Route::getRoutes()->getByName('filament.slug-tenancy.home'))->toBeNull();
|
||||
});
|
||||
@@ -29,6 +29,7 @@ use Filament\Tests\Fixtures\Providers\Fixtures\Providers\SingleDomainPanel;
|
||||
use Filament\Tests\Fixtures\Providers\MultiDomainPanel;
|
||||
use Filament\Tests\Fixtures\Providers\RequiredMultiFactorAuthenticationPanelProvider;
|
||||
use Filament\Tests\Fixtures\Providers\SlugsPanelProvider;
|
||||
use Filament\Tests\Fixtures\Providers\SlugTenancyPanelProvider;
|
||||
use Filament\Tests\Fixtures\Providers\TenancyPanelProvider;
|
||||
use Filament\Widgets\WidgetsServiceProvider;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@@ -72,6 +73,7 @@ abstract class TestCase extends BaseTestCase
|
||||
MultiDomainPanel::class,
|
||||
SingleDomainPanel::class,
|
||||
SlugsPanelProvider::class,
|
||||
SlugTenancyPanelProvider::class,
|
||||
TenancyPanelProvider::class,
|
||||
PowerJoinsServiceProvider::class,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user