1

i would like to add options based on an argument in my import command. I thought it could work to add these in interact() but when I run

bin/console app:import test --supplier=5

I get

[Symfony\Component\Console\Exception\RuntimeException]
The "--supplier" option does not exist.

I know I could use Questions but I'd prefer options because this gives me less trouble to run the import command periodically! Here's my command:

class ImportCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this
            ->setName('app:import')
            ->addArgument('importKey', InputArgument::REQUIRED)
        ;
    }

    protected function interact(InputInterface $input, OutputInterface $output)
    {
        $key = $input->getArgument('importKey');


        // this will be handled in
        // $importProvider = $this->getContainer()->get('app.import.provider');
        // $importer = $importProvider->getImport($key);
        // $importer->configureCommand($input, $output, $this);
        // but for simplicity's sake
        if($key == 'test')
        {
            $this->addOption('supplier', null,InputOption::VALUE_REQUIRED);
        }


    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {

        $supplier = $input->getOption('supplier');

        $output->writeln("your provided suplier id is '$supplier'");
    }
}
Brucie Alpha
  • 1,135
  • 2
  • 12
  • 31

2 Answers2

0

symfony optional arguments command

<?php
 namespace sandboxBundle\Command;

 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;

 // Add the required classes
 use Symfony\Component\Console\Input\InputDefinition;
 use Symfony\Component\Console\Input\InputOption;


 class TestCommand extends Command
  {
      protected function configure()
       {
        $this
           // the name of the command (the part after "bin/console")
          ->setName('app:print-lines')
           // the short description shown while running "php bin/console list"
         ->setHelp("This command allows you to print some text in the console")
         // the full command description shown when running the command with
         ->setDescription('Prints some text into the console with given parameters.')
        // Set options
          ->setDefinition(
            new InputDefinition(array(
                new InputOption('firstline', 'a', InputOption::VALUE_REQUIRED,"The first line to be printed","Default First Line Value"),
                new InputOption('secondline', 'b', InputOption::VALUE_OPTIONAL,"The second line to be printed","Default First Line Value"),
            ))
        )
    ;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
    // outputs multiple lines to the console (adding "\n" at the end of each line)
    $output->writeln([
        'My Third Symfony command',// A line
        '============',// Another line
        '',// Empty line
    ]);

    $firstLine = $input->getOption('firstline');
    $secondline = $input->getOption('secondline');

    $output->writeln("First line value : ".$firstLine);

    if($secondline){
        $output->writeln("Second line value : ".$secondline);
    }

    // Instead of retrieve line per line every option, you can get an array of all the providen options :
    //$output->writeln(json_encode($input->getOptions()));
}
}
Robert
  • 3,373
  • 1
  • 18
  • 34
  • that doesn't meet my requirements because first and second line is defined in configure() where we don't know the import key. – Brucie Alpha Aug 26 '17 at 11:24
  • can you try addArgument('supplier', InputArgument::OPTIONAL) – Robert Aug 26 '17 at 11:29
  • that doesn't change anything because the interact() is called after the input binding... i came up with a solution and post it now... but thanks anyways – Brucie Alpha Aug 26 '17 at 12:07
0

i found a solution... most likely not the best one but it works

solution - copy the class Command declare it abstract and let it extend the old Command - copy ContainerAwareCommand and let it extend your new Command - add the code to the new Command

public function notIgnoreValidationErrors()
{
    $this->ignoreValidationErrors = false;
}

protected function configureAdditionalInput(InputInterface $input, OutputInterface $output)
{
}

-change run() to

public function run(InputInterface $input, OutputInterface $output)
{
    // force the creation of the synopsis before the merge with the app definition
    $this->getSynopsis(true);
    $this->getSynopsis(false);

    // add the application arguments and options
    $this->mergeApplicationDefinition();

    // bind the input against the command specific arguments/options
    try {
        $input->bind($this->definition);
    } catch (ExceptionInterface $e) {
        if (!$this->ignoreValidationErrors) {
            throw $e;
        }
    }

    $this->configureAdditionalInput($input, $output);

    // bind the input against the command specific arguments/options
    try {
        $input->bind($this->definition);
    } catch (ExceptionInterface $e) {
        if (!$this->ignoreValidationErrors) {
            throw $e;
        }
    }

    $this->initialize($input, $output);

    if (null !== $this->processTitle) {
        if (function_exists('cli_set_process_title')) {
            if (false === @cli_set_process_title($this->processTitle)) {
                if ('Darwin' === PHP_OS) {
                    $output->writeln('<comment>Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.</comment>');
                } else {
                    $error = error_get_last();
                    trigger_error($error['message'], E_USER_WARNING);
                }
            }
        } elseif (function_exists('setproctitle')) {
            setproctitle($this->processTitle);
        } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
            $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
        }
    }

    if ($input->isInteractive()) {
        $this->interact($input, $output);
    }

    // The command name argument is often omitted when a command is executed directly with its run() method.
    // It would fail the validation if we didn't make sure the command argument is present,
    // since it's required by the application.
    if ($input->hasArgument('command') && null === $input->getArgument('command')) {
        $input->setArgument('command', $this->getName());
    }

    $input->validate();

    if ($this->code) {
        $statusCode = call_user_func($this->code, $input, $output);
    } else {
        $statusCode = $this->execute($input, $output);
    }

    return is_numeric($statusCode) ? (int) $statusCode : 0;
}

- change your command to (ContainerAwareCommand is your new Class)

class ImportCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this
            ->setName('app:import')
            ->addArgument('importKey', InputArgument::REQUIRED)
        ;
        $this->ignoreValidationErrors();
    }

    protected function configureAdditionalInput(InputInterface $input, OutputInterface $output)
    {
        $key = $input->getArgument('importKey');

        $this->notIgnoreValidationErrors();

        // this will be handled in
        // $importProvider = $this->getContainer()->get('app.import');
        // $importer = $importProvider->getImport($key);
        // $importer->configureCommand($input, $output, $this);
        if($key == 'test')
        {
            $this->addOption('supplier', null,InputOption::VALUE_REQUIRED);
        }
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {

        $supplier = $input->getOption('supplier');

        $output->writeln("your provided suplier id is '$supplier'");
    }
}

now run command

bin/console app:import test --supplier=5

your provided suplier id is '5'

Brucie Alpha
  • 1,135
  • 2
  • 12
  • 31