From bf42a1289451b87c774cb293ead97d3f850f9451 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 26 Mar 2026 15:34:04 +0100 Subject: [PATCH 1/3] Change tenant storage listeners into jobs Also move the commented jobs to the JobPipelines and update FilesystemTenancyBootstrapperTest accordingly. --- assets/TenancyServiceProvider.stub.php | 6 ++-- .../CreateTenantStorage.php | 21 ++++++++++--- src/Jobs/DeleteTenantStorage.php | 31 +++++++++++++++++++ src/Listeners/DeleteTenantStorage.php | 20 ------------ .../FilesystemTenancyBootstrapperTest.php | 8 +++-- 5 files changed, 55 insertions(+), 31 deletions(-) rename src/{Listeners => Jobs}/CreateTenantStorage.php (51%) create mode 100644 src/Jobs/DeleteTenantStorage.php delete mode 100644 src/Listeners/DeleteTenantStorage.php diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index 1cb358de0..050a2ffcd 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -46,6 +46,7 @@ public function events() Jobs\CreateDatabase::class, Jobs\MigrateDatabase::class, // Jobs\SeedDatabase::class, + // Jobs\CreateTenantStorage::class, // Jobs\CreateStorageSymlinks::class, // Your own jobs to prepare the tenant. @@ -53,8 +54,6 @@ public function events() ])->send(function (Events\TenantCreated $event) { return $event->tenant; })->shouldBeQueued(false), - - // Listeners\CreateTenantStorage::class, ], Events\SavingTenant::class => [], Events\TenantSaved::class => [], @@ -63,12 +62,11 @@ public function events() Events\DeletingTenant::class => [ JobPipeline::make([ Jobs\DeleteDomains::class, + // Jobs\DeleteTenantStorage::class, // Jobs\RemoveStorageSymlinks::class, ])->send(function (Events\DeletingTenant $event) { return $event->tenant; })->shouldBeQueued(false), - - // Listeners\DeleteTenantStorage::class, ], Events\TenantDeleted::class => [ JobPipeline::make([ diff --git a/src/Listeners/CreateTenantStorage.php b/src/Jobs/CreateTenantStorage.php similarity index 51% rename from src/Listeners/CreateTenantStorage.php rename to src/Jobs/CreateTenantStorage.php index 3bebb7310..8e4e15a91 100644 --- a/src/Listeners/CreateTenantStorage.php +++ b/src/Jobs/CreateTenantStorage.php @@ -2,9 +2,14 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Listeners; +namespace Stancl\Tenancy\Jobs; -use Stancl\Tenancy\Events\Contracts\TenantEvent; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; +use Stancl\Tenancy\Contracts\Tenant; /** * Can be used to manually create framework directories in the tenant storage when storage_path() is scoped. @@ -13,11 +18,17 @@ * * Generally not needed anymore as the directory is also created by the FilesystemTenancyBootstrapper. */ -class CreateTenantStorage +class CreateTenantStorage implements ShouldQueue { - public function handle(TenantEvent $event): void + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + + public function __construct( + public Tenant $tenant, + ) {} + + public function handle(): void { - $storage_path = tenancy()->run($event->tenant, fn () => storage_path()); + $storage_path = tenancy()->run($this->tenant, fn () => storage_path()); $cache_path = "$storage_path/framework/cache"; if (! is_dir($cache_path)) { diff --git a/src/Jobs/DeleteTenantStorage.php b/src/Jobs/DeleteTenantStorage.php new file mode 100644 index 000000000..bbe8b08e5 --- /dev/null +++ b/src/Jobs/DeleteTenantStorage.php @@ -0,0 +1,31 @@ +run($this->tenant, fn () => storage_path()); + + if (is_dir($path)) { + File::deleteDirectory($path); + } + } +} diff --git a/src/Listeners/DeleteTenantStorage.php b/src/Listeners/DeleteTenantStorage.php deleted file mode 100644 index ec360073e..000000000 --- a/src/Listeners/DeleteTenantStorage.php +++ /dev/null @@ -1,20 +0,0 @@ -run($event->tenant, fn () => storage_path()); - - if (is_dir($path)) { - File::deleteDirectory($path); - } - } -} diff --git a/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php b/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php index 628b974e3..04b4e1ed6 100644 --- a/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php @@ -13,7 +13,7 @@ use Stancl\Tenancy\Jobs\CreateStorageSymlinks; use Stancl\Tenancy\Jobs\RemoveStorageSymlinks; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Listeners\DeleteTenantStorage; +use Stancl\Tenancy\Jobs\DeleteTenantStorage; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; use function Stancl\Tenancy\Tests\pest; @@ -185,7 +185,11 @@ }); test('tenant storage can get deleted after the tenant when DeletingTenant listens to DeleteTenantStorage', function() { - Event::listen(DeletingTenant::class, DeleteTenantStorage::class); + Event::listen(DeletingTenant::class, + JobPipeline::make([DeleteTenantStorage::class])->send(function (DeletingTenant $event) { + return $event->tenant; + })->shouldBeQueued(false)->toListener() + ); tenancy()->initialize(Tenant::create()); $tenantStoragePath = storage_path(); From 873488be55107bc0b20c242c941ecdeb16c3cb39 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 Mar 2026 14:34:27 +0000 Subject: [PATCH 2/3] Fix code style (php-cs-fixer) --- src/Jobs/DeleteTenantStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Jobs/DeleteTenantStorage.php b/src/Jobs/DeleteTenantStorage.php index bbe8b08e5..c0329c502 100644 --- a/src/Jobs/DeleteTenantStorage.php +++ b/src/Jobs/DeleteTenantStorage.php @@ -9,8 +9,8 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\File; +use Stancl\Tenancy\Contracts\Tenant; class DeleteTenantStorage implements ShouldQueue { From 5b2cce347a41251be6fb788b2406633b17a461c8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 27 Mar 2026 11:58:00 +0100 Subject: [PATCH 3/3] Add test for CreateTenantStorage --- .../FilesystemTenancyBootstrapperTest.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php b/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php index 04b4e1ed6..4594d7aa9 100644 --- a/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/FilesystemTenancyBootstrapperTest.php @@ -13,6 +13,7 @@ use Stancl\Tenancy\Jobs\CreateStorageSymlinks; use Stancl\Tenancy\Jobs\RemoveStorageSymlinks; use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Jobs\CreateTenantStorage; use Stancl\Tenancy\Jobs\DeleteTenantStorage; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; @@ -184,6 +185,26 @@ $this->assertDirectoryDoesNotExist(public_path("public-$tenantKey")); }); +test('tenant storage gets created when TenantCreated listens to CreateTenantStorage', function() { + config([ + 'tenancy.bootstrappers' => [ + FilesystemTenancyBootstrapper::class, + ], + ]); + + Event::listen(TenantCreated::class, + JobPipeline::make([CreateTenantStorage::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->shouldBeQueued(false)->toListener() + ); + + $centralStoragePath = storage_path(); + $tenant = Tenant::create(); + $tenantStoragePath = $centralStoragePath . '/tenant' . $tenant->getTenantKey(); + + $this->assertDirectoryExists($tenantStoragePath . '/framework/cache'); +}); + test('tenant storage can get deleted after the tenant when DeletingTenant listens to DeleteTenantStorage', function() { Event::listen(DeletingTenant::class, JobPipeline::make([DeleteTenantStorage::class])->send(function (DeletingTenant $event) { @@ -260,4 +281,3 @@ expect(file_get_contents(storage_path() . "/app/public/scoped_disk_prefix/foo.txt"))->toBe('central2'); expect(file_get_contents(storage_path() . "/tenant{$tenant->id}/app/public/scoped_disk_prefix/foo.txt"))->toBe('tenant'); }); -