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

137 lines
3.8 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Presentation\Console\Commands;
use Application\Security\Exceptions\ClientNameAlreadyExistsException;
use Application\Security\Models\ValueObjects\ClientName;
use Application\Security\Ports\Repositories\ClientRepository;
use Application\Security\Usecases\CreateClient\CreateClient;
use Application\Security\Usecases\CreateClient\Input;
use Illuminate\Console\Command;
use Presentation\Console\Presenters\Clients\CreateClientPresenter;
use Presentation\Console\Presenters\Clients\CreateClientView;
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
use Shared\DDD\Usecase\Builder\UsecaseExecutor;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\text;
final class CreateClientCommand extends Command
{
/**
* @var string
*/
protected $signature = 'client:create';
/**
* @var string
*/
protected $description = 'Create a new API client (interactive wizard)';
public function __construct(
private readonly ClientRepository $clientRepository,
) {
parent::__construct();
}
public function handle(
CreateClient $usecase,
UsecaseExecutor $executor,
): int {
$clientName = $this->askForClientName();
if (! $this->confirmCreation($clientName)) {
$this->warn('Client creation cancelled.');
return self::SUCCESS;
}
$view = UsecaseBuilder::using($executor)
->do($usecase)
->from($this->getInput($clientName))
->with(new CreateClientPresenter())
->run();
$this->displayCredentials($view);
return self::SUCCESS;
}
private function getInput(ClientName $clientName): Input
{
return new Input($clientName);
}
private function askForClientName(): ClientName
{
$rawName = text(
label: 'Client name (e.g. "Ones Branding website")',
placeholder: 'E.g. Ones Branding website',
required: 'Client name cannot be empty.',
validate: function (string $value): ?string {
$trimmed = trim($value);
if ($trimmed === '') {
return 'Client name cannot be empty.';
}
try {
$clientName = new ClientName($trimmed);
if ($this->clientRepository->existsByName($clientName)) {
return ClientNameAlreadyExistsException::forName($clientName)->getMessage();
}
} catch (\InvalidArgumentException $e) {
return $e->getMessage();
}
return null;
},
);
return new ClientName(trim($rawName));
}
private function confirmCreation(ClientName $name): bool
{
$this->newLine();
$this->info('Summary:');
$this->table(
['Field', 'Value'],
[
['Name', $name->value],
['Identifier', '<auto-generated>'],
['Secret', '<auto-generated>'],
['Status', 'Active'],
],
);
return confirm(
label: 'Create this API client?',
default: false,
);
}
private function displayCredentials(CreateClientView $view): void
{
$this->newLine();
$this->info($view->message);
$this->newLine();
$this->table(
['Field', 'Value'],
[
['ID', $view->id],
['Name', $view->name],
['Identifier', $view->identifier],
['Secret', $view->secret],
],
);
$this->newLine();
$this->warn('WARNING: Store the secret securely, it cannot be retrieved later.');
}
}