singleloginsystem/app/Services/ConnectionProviderService.php
= 42737a6a2f Feat: integrate reusable confirmation logic across components
- Applied `Confirmation` trait to multiple Livewire components for unified confirmation handling.
- Replaced inline confirmation modals with `requireConfirmation` method for streamlined interaction.
- Updated button styles and added reusable confirmation prompts for delete/detach actions.
- Enhanced `AppRoleService` and `ConnectionProviderService` to support deletion with confirmation.
2026-05-22 12:59:12 +00:00

128 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use App\Data\ConnectedApp\{ConnectionProviderData, StoreConnectionProviderRequestData};
use App\Models\ConnectionProvider;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use NoDiscard;
use Spatie\LaravelData\PaginatedDataCollection;
use Throwable;
class ConnectionProviderService
{
public function __construct(
private readonly AppRoleService $appRoleService,
) {}
/**
* @return Collection<int, ConnectionProvider>
*/
#[NoDiscard]
public function search(string $value): Collection
{
return ConnectionProvider::query()
->whereLike('slug', "%{$value}%")
->orWhereLike('name', "%{$value}%")
->get();
}
/**
* @throws Throwable
*/
public function create(StoreConnectionProviderRequestData $data): void
{
DB::transaction(
function () use ($data): void {
ConnectionProvider::query()->create($data->toArray());
}
);
}
/**
* @return PaginatedDataCollection<int, ConnectionProviderData>
*/
#[NoDiscard]
public function getAll(): PaginatedDataCollection
{
$data = ConnectionProvider::query()->select(['id', 'name', 'slug'])->paginate();
return ConnectionProviderData::collect($data, PaginatedDataCollection::class);
}
/**
* @throws InvalidArgumentException when id is invalid
* @throws Throwable when an error occurs during the update.
*/
public function update(string $slug, StoreConnectionProviderRequestData $data): void
{
DB::transaction(
function () use ($slug, $data): void {
$app = ConnectionProvider::query()
->where('slug', $slug);
$app->update($data->toArray());
}
);
}
/**
* Delete the connection provider and associated connected apps.
*
* @throws ModelNotFoundException when the connection provider is not found.
* @throws Throwable when an error occurs during the deletion.
*/
public function delete(string $slug): void
{
DB::transaction(
function () use ($slug): void {
$provider = ConnectionProvider::query()
->where('slug', $slug)
->firstOrFail();
$deletedApps = $provider->connectedApps()
->select(['id', 'name'])
->get()
->toArray();
$this->appRoleService->detachApps(array_column($deletedApps, 'id'));
// Note: This performs a mass soft-delete query.
// Model events for ConnectedApp will NOT fire.
$provider->connectedApps()->delete();
// Stop the default logging
$provider->disableLogging()->delete();
activity()
->performedOn($provider)
->event('provider_cascade_deleted')
->withProperties([
'slug' => $slug,
'name' => $provider->name,
'deleted_apps_count' => count($deletedApps),
'deleted_apps' => $deletedApps,
])
->log(":causer.name Deleted connection provider '{$provider->name}' alongside ".count($deletedApps).' connected apps.');
}
);
}
/**
* @throws ModelNotFoundException<ConnectionProviderData> when the connected app is not found.
* @throws InvalidArgumentException when id is invalid.
*/
#[NoDiscard]
public function getProvider(string $slug): ConnectionProviderData
{
$data = ConnectionProvider::query()
->select(['id', 'name', 'slug'])
->where('slug', $slug)
->first();
return ConnectionProviderData::from($data);
}
}