Create generic command with builder to easily edit entities from console

This commit is contained in:
Tim 2022-09-23 23:39:16 +02:00
parent 665f4a376e
commit 941e3cdc9c
3 changed files with 119 additions and 12 deletions

View File

@ -2,29 +2,101 @@
namespace Ardent\UtilBundle\Command;
use App\Entity\Configuration;
use Ardent\UtilBundle\EntityBuilder\Builder;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
abstract class AbstractEntityCommand extends Command
{
abstract function getConfig(): Builder;
public function __construct(
private EntityManagerInterface $em,
)
{
parent::__construct();
}
abstract function getConfig(Builder $builder): void;
abstract function getEntityClass(): string;
protected function configure(): void
{
$this
->addArgument('id', InputArgument::OPTIONAL, 'Object Id')
->addOption('create', 'c', InputOption::VALUE_NONE, 'Create entity')
->addOption('edit', 'e', InputOption::VALUE_NONE, 'Edit entity')
->addOption('modify', 'm', InputOption::VALUE_NONE, 'Edit entity')
->addOption('delete', 'd', InputOption::VALUE_NONE, 'Delete entity')
->addOption('show', 's', InputOption::VALUE_NONE, 'Show entity');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument('id');
$builder = new Builder($io);
$this->getConfig($builder);
if ($input->getOption('create')) {
$entity = new ($this->getEntityClass())();
$builder->setAll($entity);
if ($io->askQuestion(new ConfirmationQuestion(sprintf('Are you sure you want to create %s with above properties', $entity)))) {
$io->success(sprintf('Object "%s" (id: %s) stored successfully', $entity, $entity->getId()));
}
} elseif ($input->getOption('modify')) {
$entity = $this->select($io, $id);
$builder->setByQuestion($entity);
} elseif ($input->getOption('delete')) {
$entity = $this->select($io, $id);
if ($io->askQuestion(new ConfirmationQuestion(sprintf('Are you sure you want to delete %s', $entity)))) {
$name = (string)$entity;
$this->em->remove($entity);
$io->success(sprintf('Config "%s" deleted', $name));
}
} elseif ($input->getOption('show')) {
$entity = $this->select($io, $id);
$table = $io->createTable();
$table->setHeaders(['property', 'value']);
$table->setRows($builder->getAllproperties($entity));
$table->setHeaderTitle(sprintf('id: %s', $entity->getId()));
$table->render();
} else {
$io->error('Select at least one of the options');
return Command::FAILURE;
}
$this->em->persist($entity);
$this->em->flush();
return Command::SUCCESS;
}
private function select(SymfonyStyle $io, ?int $id): object
{
$repo = $this->em->getRepository($this->getEntityClass());
if ($id) {
$object = $repo->find($id);
if ($object) {
return $object;
}
}
$entities = $repo->findAll();
if (empty($entities)) {
throw new Exception('No objects found');
}
$question = new ChoiceQuestion('Select configuration to delete', $entities);
return $io->askQuestion($question);
}
}

View File

@ -4,7 +4,7 @@ namespace Ardent\UtilBundle\EntityBuilder;
use Symfony\Component\Console\Question\Question;
class SimpleElement
class BaseElement
{
public function getQuestion(): Question
{
@ -23,4 +23,9 @@ class SimpleElement
{
return $this->property;
}
public function __toString(): string
{
return $this->property;
}
}

View File

@ -3,39 +3,69 @@
namespace Ardent\UtilBundle\EntityBuilder;
use Exception;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
class Builder
{
/**
* @var SimpleElement[]
* @var BaseElement[]
*/
private array $elements = [];
public function __construct(
private readonly SymfonyStyle $io,
)
{
}
public function add(SimpleElement|string $element): self
public function add(BaseElement|string $element): self
{
if (is_string($element)) {
$element = new SimpleElement($element);
$element = new BaseElement($element);
}
$this->elements[] = $element;
return $this;
}
public function setObject(mixed $object): void
private function getPopertyNames(): array
{
return array_map(fn(BaseElement $element) => $element->getProperty(), $this->elements);
}
private function setProperty(object $object, BaseElement $element): void
{
foreach ($this->elements as $element) {
$setter = sprintf('set%s', ucfirst($element->getProperty()));
if (!method_exists($object, $setter)) {
throw new Exception(sprintf('Object does not have setter "%s"', $setter));
}
$object->$setter($this->io->askQuestion($element->getQuestion()));
}
public function setAll(object $object): void
{
foreach ($this->elements as $element) {
$this->setProperty($object, $element);
}
}
public function setByQuestion(object $object): void
{
$element = $this->io->askQuestion(new ChoiceQuestion('Select property to modify', $this->elements));
$getter = sprintf('get%s', ucfirst($element->getProperty()));
$this->io->writeln(sprintf('Current value: %s', $object->$getter()));
$this->setProperty($object, $element);
}
public function getAllproperties(object $object): array
{
$data = [];
foreach ($this->elements as $element) {
$getter = sprintf('get%s', ucfirst($element->getProperty()));
$data[] = [$element->getProperty(), $object->$getter()];
}
return $data;
}
}