diff --git a/src/ResourceSyncing/TriggerSyncingEvents.php b/src/ResourceSyncing/TriggerSyncingEvents.php index 2f8914b5..059eb579 100644 --- a/src/ResourceSyncing/TriggerSyncingEvents.php +++ b/src/ResourceSyncing/TriggerSyncingEvents.php @@ -7,6 +7,7 @@ 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; @@ -85,7 +86,7 @@ trait TriggerSyncingEvents } if ($this instanceof MorphPivot) { - return $this->morphClass; + return Relation::getMorphedModel($this->morphClass) ?? $this->morphClass; } throw new CentralResourceNotAvailableInPivotException; diff --git a/tests/ResourceSyncingTest.php b/tests/ResourceSyncingTest.php index 826ed780..11a172c5 100644 --- a/tests/ResourceSyncingTest.php +++ b/tests/ResourceSyncingTest.php @@ -52,6 +52,7 @@ use Stancl\Tenancy\Events\TenantDeleted; use Stancl\Tenancy\ResourceSyncing\Events\SyncedResourceDeleted; use Stancl\Tenancy\ResourceSyncing\Listeners\DeleteAllTenantMappings; use Stancl\Tenancy\ResourceSyncing\Listeners\DeleteResourceMapping; +use Illuminate\Database\Eloquent\Relations\Relation; beforeEach(function () { config(['tenancy.bootstrappers' => [ @@ -1364,6 +1365,53 @@ test('global scopes on syncable models can break resource syncing', function () expect($tenant1->run(fn () => TenantUser::first()->name))->toBe('tenant2 user'); }); +test('attach and detach events are handled correctly when using morph maps', function() { + config(['tenancy.models.tenant' => MorphTenant::class]); + [$tenant] = createTenantsAndRunMigrations(); + migrateCompaniesTableForTenants(); + + Relation::morphMap([ + 'users' => BaseCentralUser::class, + 'companies' => CentralCompany::class, + ]); + + $centralUser = BaseCentralUser::create([ + 'global_id' => 'user', + 'name' => 'Central user', + 'email' => 'central@localhost', + 'password' => 'password', + 'role' => 'user', + ]); + + $centralCompany = CentralCompany::create([ + 'global_id' => 'company', + 'name' => 'Central company', + 'email' => 'company@localhost', + ]); + + $tenant->users()->attach($centralUser); + $tenant->companies()->attach($centralCompany); + + // Assert all tenant_resources mappings actually use the configured morph map + expect(DB::table('tenant_resources')->count()) + ->toBe(DB::table('tenant_resources')->whereIn('tenant_resources_type', ['users', 'companies'])->count()); + + tenancy()->initialize($tenant); + + expect(BaseTenantUser::whereGlobalId('user')->first())->not()->toBeNull(); + expect(TenantCompany::whereGlobalId('company')->first())->not()->toBeNull(); + + tenancy()->end(); + + $tenant->users()->detach($centralUser); + $tenant->companies()->detach($centralCompany); + + tenancy()->initialize($tenant); + + expect(BaseTenantUser::whereGlobalId('user')->first())->toBeNull(); + expect(TenantCompany::whereGlobalId('company')->first())->toBeNull(); +}); + function addTenantIdConstraintToPivot(string $pivotTable): void { Schema::table($pivotTable, function (Blueprint $table) {