Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/ResourceSyncing/Listeners/DeletesSyncedResources.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Stancl\Tenancy\ResourceSyncing\Listeners;

use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Stancl\Tenancy\ResourceSyncing\Syncable;
use Stancl\Tenancy\ResourceSyncing\SyncMaster;

trait DeletesSyncedResources
Expand All @@ -14,16 +14,20 @@ protected function deleteSyncedResource(SyncMaster&Model $centralResource, bool
{
$tenantResourceClass = $centralResource->getTenantModelName();

/** @var (Syncable&Model)|null $tenantResource */
$tenantResource = $tenantResourceClass::firstWhere(
/** @var Builder $query */
$query = $tenantResourceClass::where(
$centralResource->getGlobalIdentifierKeyName(),
$centralResource->getGlobalIdentifierKey()
);

if ($force) {
$tenantResource?->forceDelete();
if ($query->hasMacro('withTrashed')) {
$query->withTrashed(); // @phpstan-ignore method.notFound
}

$query->first()?->forceDelete();
} else {
$tenantResource?->delete();
$query->first()?->delete();
}
}
}
71 changes: 71 additions & 0 deletions tests/ResourceSyncingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,77 @@
expect(TenantUserWithSoftDeletes::withTrashed()->firstWhere('global_id', 'user'))->toBeNull();
});

test('force deleting a central resource force deletes tenant resources that are already trashed', function () {
[$tenant1] = createTenantsAndRunMigrations();
migrateUsersTableForTenants();
addExtraColumns(true);

foreach ([
fn ($user, $tenant) => $user->forceDelete(),
fn ($user, $tenant) => $user->tenants()->detach($tenant),
] as $triggerForceDelete) {
$centralUser = CentralUserWithSoftDeletes::create([
'global_id' => 'user',
'name' => 'Central user',
'email' => 'central@localhost',
'password' => 'password',
'role' => 'commenter',
'foo' => 'foo',
]);

$centralUser->tenants()->attach($tenant1);

tenancy()->initialize($tenant1);

TenantUserWithSoftDeletes::firstWhere('global_id', 'user')->delete();

tenancy()->end();

$triggerForceDelete($centralUser, $tenant1);

tenancy()->initialize($tenant1);

expect(TenantUserWithSoftDeletes::withTrashed()->firstWhere('global_id', 'user'))->toBeNull();
Comment thread
lukinovec marked this conversation as resolved.

tenancy()->end();
}
});

test('trashing a central resource does not affect tenant resources that are already trashed', function () {
[$tenant1] = createTenantsAndRunMigrations();
migrateUsersTableForTenants();
addExtraColumns(true);

$centralUser = CentralUserWithSoftDeletes::create([
'global_id' => 'user',
'name' => 'Central user',
'email' => 'central@localhost',
'password' => 'password',
'role' => 'commenter',
'foo' => 'foo',
]);

$centralUser->tenants()->attach($tenant1);

tenancy()->initialize($tenant1);

// Trash the tenant resource a day in the past so that deleting it again would update deleted_at
$this->travelTo(now()->subDay());

TenantUserWithSoftDeletes::firstWhere('global_id', 'user')->delete();

$this->travelBack();

$tenantUserDeletedAt = TenantUserWithSoftDeletes::withTrashed()->firstWhere('global_id', 'user')->deleted_at;

expect($tenantUserDeletedAt)->not()->toBeNull();

// Trashing the central resource doesn't touch already trashed tenant resources
$centralUser->delete();

expect(TenantUserWithSoftDeletes::withTrashed()->firstWhere('global_id', 'user')->deleted_at)->toEqual($tenantUserDeletedAt);
});

test('resource creation works correctly when tenant resource provides defaults in the creation attributes', function () {
[$tenant1, $tenant2] = createTenantsAndRunMigrations();

Expand Down
Loading