refactor(integration): enhance association logic to delete unused instances and improve transaction handling
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user