ldc-arcadia-api/src/Presentation/Console/Commands/ToggleClientStatusCommand.php

162 lines
4.8 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Presentation\Console\Commands;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Usecases\ToggleClientStatus\Input;
use Application\Security\Usecases\ToggleClientStatus\SetClientStatus;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Presentation\Console\Presenters\Clients\SetClientStatusPresenter;
use Presentation\Console\Services\ClientConsoleResolver;
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
use Shared\DDD\Usecase\Builder\UsecaseExecutor;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use function Laravel\Prompts\search;
final class ToggleClientStatusCommand extends Command implements PromptsForMissingInput
{
/**
* @var string
*/
protected $signature = 'arcadia:client:toggle-status
{identifier : The identifier of the client}
{status? : The desired status of the client (activate|deactivate)}';
/**
* @var string
*/
protected $description = 'Toggle the status of an API client';
public function __construct(
private readonly ClientConsoleResolver $clientResolver,
) {
parent::__construct();
}
/**
* @return array<string, \Closure(): (int|string)>
*/
#[\Override]
protected function promptForMissingArgumentsUsing(): array
{
return [
'identifier' => fn (): int | string => search(
label: 'Search client (by name, ID, identifier, or slug):',
placeholder: 'Type client name, identifier or slug...',
options: fn (string $value): array => $this->clientResolver->searchOptions($value),
scroll: 10,
),
];
}
#[\Override]
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestArgumentValuesFor('identifier')) {
$this->clientResolver->complete($suggestions);
}
if ($input->mustSuggestArgumentValuesFor('status')) {
$suggestions->suggestValues([
new Suggestion('activate', 'Activate the client'),
new Suggestion('deactivate', 'Deactivate the client'),
]);
}
}
public function handle(
SetClientStatus $usecase,
UsecaseExecutor $executor,
): int {
$input = $this->getInput();
if ($input === null) {
return self::FAILURE;
}
try {
$view = UsecaseBuilder::using($executor)
->do($usecase)
->from($input)
->with(new SetClientStatusPresenter())
->run();
$this->info($view->message);
return self::SUCCESS;
} catch (ClientNotFoundException | \InvalidArgumentException $e) {
$this->error($e->getMessage());
return self::FAILURE;
}
}
private function getInput(): ?Input
{
$client = $this->resolveClient();
if ($client === null) {
return null;
}
try {
$desiredStatus = $this->resolveDesiredStatus($client);
return new Input($client->identifier, $desiredStatus);
} catch (\InvalidArgumentException $e) {
$this->error($e->getMessage());
return null;
}
}
private function resolveClient(): ?Client
{
$raw = $this->argument('identifier');
if (! is_string($raw) || trim($raw) === '') {
$this->error('No client specified.');
return null;
}
$inputString = trim($raw);
$client = $this->clientResolver->find($inputString);
if ($client !== null) {
return $client;
}
try {
new ClientIdentifier($inputString);
$this->error("Client '{$inputString}' not found.");
} catch (\InvalidArgumentException) {
$this->error("Invalid client identifier '{$inputString}'. Expected a valid client identifier.");
}
return null;
}
private function resolveDesiredStatus(Client $client): bool
{
$status = $this->argument('status') !== null ? (string) $this->argument('status') : null;
return match ($status) {
'activate' => true,
'deactivate' => false,
null => ! $client->isActive,
default => throw new \InvalidArgumentException("Invalid status '{$status}'. Expected 'activate' or 'deactivate'."),
};
}
}