1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-08-06 05:54:03 +00:00
tenancy/src/ResourceSyncing/TriggerSyncingEvents.php
lukinovec d2fb4bc0d5 Only trigger pivot attach on creation (not on updates)
Use created() instead of saved() in TriggerSyncingEvents so that updating
pivot columns no longer attempts to attach. Attaching re-created the tenant
resource and caused a duplicate entry error (detaching already uses deleting(),
so using created() is more consistent with that anyway)
2026-07-07 12:42:16 +02:00

112 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Stancl\Tenancy\ResourceSyncing;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphPivot;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Relations\Relation;
use Stancl\Tenancy\Contracts\Tenant;
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
/**
* Used on pivot models.
*
* @see TenantPivot
* @see MorphPivot
*/
trait TriggerSyncingEvents
{
public static function bootTriggerSyncingEvents(): void
{
static::saving(static function (self $pivot) {
// Try getting the central resource to see if it is available
// If it is not available, throw an exception to interrupt the saving process
// And prevent creating a pivot record without a central resource
$pivot->getCentralResourceAndTenant();
});
// Only attach when the pivot is created
static::created(static function (self $pivot) {
/**
* @var static&Pivot $pivot
* @var SyncMaster|null $centralResource
* @var (TenantWithDatabase&Model)|null $tenant
*/
[$centralResource, $tenant] = $pivot->getCentralResourceAndTenant();
if ($tenant && $centralResource?->shouldSync()) {
$centralResource->triggerAttachEvent($tenant);
}
});
static::deleting(static function (self $pivot) {
/**
* @var static&Pivot $pivot
* @var SyncMaster|null $centralResource
* @var (TenantWithDatabase&Model)|null $tenant
*/
[$centralResource, $tenant] = $pivot->getCentralResourceAndTenant();
if ($tenant && $centralResource?->shouldSync()) {
$centralResource->triggerDetachEvent($tenant);
}
});
}
public function getCentralResourceAndTenant(): array
{
/** @var $this&Pivot $this */
$parent = $this->pivotParent;
if ($parent instanceof Tenant) {
// Tenant is the parent
// $tenant->attach($resource) / $tenant->detach($resource)
return [$this->findCentralResource(), $parent];
}
// Central resource is the parent
// $centralResource->attach($tenant) / $centralResource->detach($tenant)
return [$parent, tenancy()->find($this->{$this->getOtherKey()})];
}
/**
* Get the resource class if available. Otherwise, throw an exception.
*
* Used in the `findCentralResource` method.
*
* @throws CentralResourceNotAvailableInPivotException
*/
protected function getResourceClass(): string
{
/** @var $this&(Pivot|MorphPivot|((Pivot|MorphPivot)&PivotWithCentralResource)) $this */
if ($this instanceof PivotWithCentralResource) {
return $this->getCentralResourceClass();
}
if ($this instanceof MorphPivot) {
return Relation::getMorphedModel($this->morphClass) ?? $this->morphClass;
}
throw new CentralResourceNotAvailableInPivotException;
}
protected function findCentralResource(): (SyncMaster&Model)|null
{
/**
* Create an instance of the central resource class so that we can get the global identifier key name properly.
*
* @var SyncMaster&Model $centralResourceModel
*/
$centralResourceModel = new ($this->getResourceClass());
$globalId = $this->{$this->getOtherKey()};
/** @var (SyncMaster&Model)|null $centralResource */
$centralResource = $centralResourceModel::firstWhere($centralResourceModel->getGlobalIdentifierKeyName(), $globalId);
return $centralResource;
}
}