mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-13 22:14:03 +00:00
Syncing: SyncedResourceDeleted event and DeleteResourceMapping listener
Also move pivot record deletion to that listener and improve tests The 'tenant pivot records are deleted along with the tenants to which they belong to' test is failing in this commit -- the listener for deleting mappings when a *tenant* is deleted is only implemented in the next commit. The only change done here is to re-add FKs (necessary for passing *in this commit* in that specific dataset variant) that were removed from the default test migration as we now have the the DeleteResourceMapping listener that's enabled by default.
This commit is contained in:
parent
45cf7029af
commit
ee0b45d800
10 changed files with 135 additions and 17 deletions
18
src/ResourceSyncing/Events/SyncedResourceDeleted.php
Normal file
18
src/ResourceSyncing/Events/SyncedResourceDeleted.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\ResourceSyncing\Events;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
||||
use Stancl\Tenancy\ResourceSyncing\Syncable;
|
||||
|
||||
class SyncedResourceDeleted
|
||||
{
|
||||
public function __construct(
|
||||
public Syncable&Model $model,
|
||||
public TenantWithDatabase|null $tenant,
|
||||
public bool $forceDelete,
|
||||
) {}
|
||||
}
|
||||
60
src/ResourceSyncing/Listeners/DeleteResourceMapping.php
Normal file
60
src/ResourceSyncing/Listeners/DeleteResourceMapping.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\ResourceSyncing\Listeners;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Stancl\Tenancy\Listeners\QueueableListener;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncedResourceDeleted;
|
||||
use Stancl\Tenancy\ResourceSyncing\Syncable;
|
||||
use Stancl\Tenancy\ResourceSyncing\SyncMaster;
|
||||
|
||||
/**
|
||||
* Deletes pivot records when a synced resource is deleted.
|
||||
*
|
||||
* If a SyncMaster (central resource) is deleted, all pivot records for that resource are deleted.
|
||||
* If a Syncable (tenant resource) is deleted, only delete the pivot record for that tenant.
|
||||
*/
|
||||
class DeleteResourceMapping extends QueueableListener
|
||||
{
|
||||
public static bool $shouldQueue = false;
|
||||
|
||||
public function handle(SyncedResourceDeleted $event): void
|
||||
{
|
||||
$centralResource = $this->getCentralResource($event->model);
|
||||
|
||||
if (! $centralResource) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete pivot records if the central resource doesn't use soft deletes
|
||||
// or the central resource was deleted using forceDelete()
|
||||
if ($event->forceDelete || ! in_array(SoftDeletes::class, class_uses_recursive($centralResource::class), true)) {
|
||||
Pivot::withoutEvents(function () use ($centralResource, $event) {
|
||||
// $event->tenant is null when the deleted resource is a SyncMaster - all mappings are deleted in that case
|
||||
// When $event->tenant is not null (= a Syncable was deleted), only delete the mapping for that tenant
|
||||
$centralResource->tenants()->detach($event->tenant);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function getCentralResource(Syncable&Model $resource): SyncMaster|null
|
||||
{
|
||||
if ($resource instanceof SyncMaster) {
|
||||
return $resource;
|
||||
}
|
||||
|
||||
$centralResourceClass = $resource->getCentralModelName();
|
||||
|
||||
/** @var (SyncMaster&Model)|null $centralResource */
|
||||
$centralResource = $centralResourceClass::firstWhere(
|
||||
$resource->getGlobalIdentifierKeyName(),
|
||||
$resource->getGlobalIdentifierKey()
|
||||
);
|
||||
|
||||
return $centralResource;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Stancl\Tenancy\ResourceSyncing\Listeners;
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Stancl\Tenancy\Listeners\QueueableListener;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncMasterDeleted;
|
||||
|
||||
|
|
@ -21,12 +20,6 @@ class DeleteResourcesInTenants extends QueueableListener
|
|||
|
||||
tenancy()->runForMultiple($centralResource->tenants()->cursor(), function () use ($centralResource, $forceDelete) {
|
||||
$this->deleteSyncedResource($centralResource, $forceDelete);
|
||||
|
||||
// Delete pivot records if the central resource doesn't use soft deletes
|
||||
// or the central resource was deleted using forceDelete()
|
||||
if ($forceDelete || ! in_array(SoftDeletes::class, class_uses_recursive($centralResource::class), true)) {
|
||||
$centralResource->tenants()->detach(tenant());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator;
|
|||
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\CentralResourceAttachedToTenant;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\CentralResourceDetachedFromTenant;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncedResourceDeleted;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncedResourceSaved;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncMasterDeleted;
|
||||
use Stancl\Tenancy\ResourceSyncing\Events\SyncMasterRestored;
|
||||
|
|
@ -25,8 +26,8 @@ trait ResourceSyncing
|
|||
}
|
||||
});
|
||||
|
||||
static::deleting(function (Syncable&Model $model) {
|
||||
if ($model->shouldSync() && $model instanceof SyncMaster) {
|
||||
static::deleted(function (Syncable&Model $model) {
|
||||
if ($model->shouldSync()) {
|
||||
$model->triggerDeleteEvent();
|
||||
}
|
||||
});
|
||||
|
|
@ -42,13 +43,13 @@ trait ResourceSyncing
|
|||
|
||||
if (in_array(SoftDeletes::class, class_uses_recursive(static::class), true)) {
|
||||
static::forceDeleting(function (Syncable&Model $model) {
|
||||
if ($model->shouldSync() && $model instanceof SyncMaster) {
|
||||
if ($model->shouldSync()) {
|
||||
$model->triggerDeleteEvent(true);
|
||||
}
|
||||
});
|
||||
|
||||
static::restoring(function (Syncable&Model $model) {
|
||||
if ($model->shouldSync() && $model instanceof SyncMaster) {
|
||||
if ($model->shouldSync()) {
|
||||
$model->triggerRestoredEvent();
|
||||
}
|
||||
});
|
||||
|
|
@ -67,6 +68,8 @@ trait ResourceSyncing
|
|||
/** @var SyncMaster&Model $this */
|
||||
event(new SyncMasterDeleted($this, $forceDelete));
|
||||
}
|
||||
|
||||
event(new SyncedResourceDeleted($this, tenant(), $forceDelete));
|
||||
}
|
||||
|
||||
public function triggerRestoredEvent(): void
|
||||
|
|
|
|||
|
|
@ -25,7 +25,5 @@ interface SyncMaster extends Syncable
|
|||
|
||||
public function triggerAttachEvent(TenantWithDatabase&Model $tenant): void;
|
||||
|
||||
public function triggerDeleteEvent(bool $forceDelete = false): void;
|
||||
|
||||
public function triggerRestoredEvent(): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ interface Syncable
|
|||
|
||||
public function triggerSyncEvent(): void;
|
||||
|
||||
public function triggerDeleteEvent(bool $forceDelete = false): void;
|
||||
|
||||
/**
|
||||
* Get the attributes used for creating the *other* model (i.e. tenant if this is the central one, and central if this is the tenant one).
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue