refactor(integration): enhance association logic to delete unused instances and improve transaction handling

This commit is contained in:
2026-09-07 11:09:08 -03:00
parent bb1f9c8e91
commit d0625f25e5
3 changed files with 88 additions and 7 deletions

View File

@@ -27,17 +27,68 @@ class IntegrationAssociationService
public function associate(Client|WebsiteType $owner, string $code, IntegrationInstance $instance): ClientIntegration|WebsiteTypeIntegration
{
abort_unless($instance->integration_code === $code, 422, 'The instance belongs to another integration.');
return DB::transaction(function () use ($owner, $code, $instance): ClientIntegration|WebsiteTypeIntegration {
$association = $owner->integrations()
->where('integration_code', $code)
->lockForUpdate()
->first();
$previousInstanceId = $association?->integration_instance_id;
return $owner->integrations()->updateOrCreate(
['integration_code' => $code],
['integration_instance_id' => $instance->id],
)->load('integrationInstance');
$instanceIds = array_values(array_unique(array_filter([
$previousInstanceId,
$instance->id,
])));
sort($instanceIds);
$instances = IntegrationInstance::query()
->whereKey($instanceIds)
->orderBy('id')
->lockForUpdate()
->get()
->keyBy('id');
$instance = $instances->get($instance->id) ?? IntegrationInstance::query()->findOrFail($instance->id);
abort_unless($instance->integration_code === $code, 422, 'The instance belongs to another integration.');
$association = $owner->integrations()->updateOrCreate(
['integration_code' => $code],
['integration_instance_id' => $instance->id],
);
if ($previousInstanceId && $previousInstanceId !== $instance->id) {
$this->deleteIfUnused($previousInstanceId);
}
return $association->load('integrationInstance');
});
}
public function detach(Client|WebsiteType $owner, string $code): void
{
$owner->integrations()->where('integration_code', $code)->delete();
DB::transaction(function () use ($owner, $code): void {
$association = $owner->integrations()
->where('integration_code', $code)
->lockForUpdate()
->first();
if (! $association) {
return;
}
$instanceId = $association->integration_instance_id;
$association->delete();
$this->deleteIfUnused($instanceId);
});
}
private function deleteIfUnused(int $instanceId): void
{
$instance = IntegrationInstance::query()->lockForUpdate()->find($instanceId);
if ($instance
&& ! $instance->clientIntegrations()->exists()
&& ! $instance->websiteTypeIntegrations()->exists()) {
$instance->delete();
}
}
private function ownerName(Client|WebsiteType $owner): string