From 30ee4e952982faff0d442d14fafe88731488383c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Fri, 14 Feb 2025 08:19:02 +0100 Subject: [PATCH] [4.x] Fix 1267: early return in runForMultiple if an empty array is passed (#1286) * fix 1267: early return in runForMultiple if an empty array is passed * Test that runForMulltiple runs the passed closure for the right tenants * Correct comment --------- Co-authored-by: lukinovec --- src/Tenancy.php | 6 ++- tests/RunForMultipleTest.php | 73 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 tests/RunForMultipleTest.php diff --git a/src/Tenancy.php b/src/Tenancy.php index 7e5094816..31947dbea 100644 --- a/src/Tenancy.php +++ b/src/Tenancy.php @@ -204,8 +204,10 @@ public function runForMultiple($tenants, Closure $callback): void // Wrap string in array $tenants = is_string($tenants) ? [$tenants] : $tenants; - // Use all tenants if $tenants is falsy - $tenants = $tenants ?: $this->model()->cursor(); // todo@phpstan phpstan thinks this isn't needed, but tests fail without it + // If $tenants is falsy by this point (e.g. an empty array) there's no work to be done + if (! $tenants) { + return; + } $originalTenant = $this->tenant; diff --git a/tests/RunForMultipleTest.php b/tests/RunForMultipleTest.php new file mode 100644 index 000000000..c82385f6c --- /dev/null +++ b/tests/RunForMultipleTest.php @@ -0,0 +1,73 @@ +send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + config(['tenancy.bootstrappers' => [ + DatabaseTenancyBootstrapper::class, + ]]); +}); + +test('runForMultiple runs the passed closure for the right tenants', function() { + $tenants = [Tenant::create(), Tenant::create(), Tenant::create()]; + + $createUser = fn ($username) => function () use ($username) { + User::create(['name' => $username, 'email' => Str::random(8) . '@example.com', 'password' => bcrypt('password')]); + }; + + // tenancy()->runForMultiple([], ...) shouldn't do anything + // No users should be created -- the closure should not run at all + tenancy()->runForMultiple([], $createUser('none')); + // Try the same with an empty collection -- the result should be the same for any traversable + tenancy()->runForMultiple(collect(), $createUser('none')); + + foreach ($tenants as $tenant) { + $tenant->run(function() { + expect(User::count())->toBe(0); + }); + } + + // tenancy()->runForMultiple(['foo', 'bar'], ...) should run the closure only for the passed tenants + tenancy()->runForMultiple([$tenants[0]->getTenantKey(), $tenants[1]->getTenantKey()], $createUser('user')); + + // User should be created for tenants[0] and tenants[1], but not for tenants[2] + foreach ($tenants as $tenant) { + $tenant->run(function() use ($tenants) { + if (tenant()->getTenantKey() !== $tenants[2]->getTenantKey()) { + expect(User::first()->name)->toBe('user'); + } else { + expect(User::count())->toBe(0); + } + }); + } + + // tenancy()->runForMultiple(null, ...) should run the closure for all tenants + tenancy()->runForMultiple(null, $createUser('new_user')); + + foreach ($tenants as $tenant) { + $tenant->run(function() { + expect(User::all()->pluck('name'))->toContain('new_user'); + }); + } +});