parent
7d21bb492c
commit
26815fcac3
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\CliProgram;
|
||||
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Helper class for command/application output
|
||||
*/
|
||||
abstract class OutputHelper {
|
||||
/**
|
||||
* Get the “error” output if exists, else the output itself
|
||||
*
|
||||
* @param OutputInterface $output The output
|
||||
*
|
||||
* @return OutputInterface The “error” output if exists, else the output itself
|
||||
*/
|
||||
public static final function getErrorOutput (OutputInterface $output): OutputInterface {
|
||||
return $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\CliProgram\Requirements;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Interface for a command requirements
|
||||
*/
|
||||
interface IRequirements {
|
||||
/**
|
||||
* Check the requirements
|
||||
*
|
||||
* @param InputInterface $input The command input
|
||||
* @param OutputInterface $output The command output
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Throwable If a requirement failed
|
||||
*/
|
||||
public function checkRequirements (InputInterface $input, OutputInterface $output): void;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\CliProgram\Requirements;
|
||||
|
||||
use jrosset\CliProgram\OutputHelper;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleCommandEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* An application with command requirements checking
|
||||
*
|
||||
* @see IRequirements
|
||||
*/
|
||||
trait TRequirementsApplication {
|
||||
/**
|
||||
* Register the listener for command requirements
|
||||
*
|
||||
* @param EventDispatcherInterface|null $dispatcher The event dispatcher is already existing
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected final function registerCommandRequirementsListener (?EventDispatcherInterface $dispatcher = null): void {
|
||||
$dispatcher ??= new EventDispatcher();
|
||||
$dispatcher->addListener(ConsoleEvents::COMMAND, $this->checkCommandRequirements(...));
|
||||
$this->setDispatcher($dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the requirements of a command
|
||||
*
|
||||
* @param ConsoleCommandEvent $event The command event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function checkCommandRequirements (ConsoleCommandEvent $event): void {
|
||||
$commandInput = $event->getInput();
|
||||
$commandOutput = $event->getOutput();
|
||||
try {
|
||||
//region Check the command is valid
|
||||
if (($command = $event->getCommand()) === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$commandReflection = new ReflectionClass($command);
|
||||
//endregion
|
||||
//region Check attribute requirements
|
||||
foreach ($commandReflection->getAttributes(IRequirements::class, ReflectionAttribute::IS_INSTANCEOF) as $commandRequirementsAttribute) {
|
||||
/** @var IRequirements $commandRequirementsAttributeInstance */
|
||||
$commandRequirementsAttributeInstance = $commandRequirementsAttribute->newInstance();
|
||||
$commandRequirementsAttributeInstance->checkRequirements($commandInput, $commandOutput);
|
||||
}
|
||||
//endregion
|
||||
//region Contrôle pré-requis (implémentation directe)
|
||||
if ($command instanceof IRequirements) {
|
||||
$command->checkRequirements($commandInput, $commandOutput);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
catch (Throwable $exception) {
|
||||
$this->renderThrowable($exception, OutputHelper::getErrorOutput($commandOutput));
|
||||
|
||||
$event->disableCommand();
|
||||
$event->stopPropagation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\Tests\Commands;
|
||||
|
||||
use jrosset\Tests\FailedRequirement;
|
||||
|
||||
#[FailedRequirement]
|
||||
class FailedHello extends Hello {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct () {
|
||||
parent::__construct('failedHello');
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\Tests;
|
||||
|
||||
use Attribute;
|
||||
use jrosset\CliProgram\Requirements\IRequirements;
|
||||
use LogicException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
class FailedRequirement implements IRequirements {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function checkRequirements (InputInterface $input, OutputInterface $output): void {
|
||||
throw new LogicException('The "foo" requirement failed');
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace jrosset\Tests;
|
||||
|
||||
use Attribute;
|
||||
use jrosset\CliProgram\Requirements\IRequirements;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
class SuccessRequirement implements IRequirements {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function checkRequirements (InputInterface $input, OutputInterface $output): void {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue