Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable number of options for symfony/console component

Tags:

php

symfony

How would one configure symfony/console to accept a dynamic list of options?

That said - the names for the options aren't known on development step so I need an application to accept everything and expose it using the standard $input->getOption.

Any chance it can be done easily (without hacking the component in million places)?

My attempts included extending the ArgvInput and InputDefinition classes but they failed due to various reasons (they are objective and symfony/console component implementation-specific). Briefly: the former requires parsing to be invoked multiple times; the latter - is instantiated in multiple places so I just couldn't find a proper way to inject it.

like image 852
zerkms Avatar asked Feb 18 '14 22:02

zerkms


3 Answers

You can create your own ArgvInput that will allow all options.

For example you can see the slightly modified version of ArgvInput here

I have only modified lines : 178

And comment out the lines: 188-199

Then pass instance of your version ArgvInput instead of default one to

$input = new AcceptAllArgvInput();    
$kernel = new AppKernel($env, $debug);
$application = new Application($kernel);
$application->run($input);
like image 108
xiidea Avatar answered Nov 09 '22 16:11

xiidea


I have accomplished this in the past using the IS_ARRAY option. Would this not work for your instance as well?

->addArgument('routeParams', InputArgument::IS_ARRAY, "Required Placeholders for route");

My use case was a custom URL generator for a special authentication system. I needed a way to generate URLs for testing. Naturally, each route has a different number of required parameters and I wanted to avoid passing the parameters as a CSV string.

Command examples: Usage: myGenerateToken user route [variables1] ... [variablesN]

 php app/console myGenerateToken 1 productHomePage
 php app/console myGenerateToken 1 getProduct 1
 php app/console myGenerateToken 1 getProductFile 1 changelog

The variables were delivered to the command in the "routeParams" as an array

 $params = $input->getArgument('routeParams');
 var_dump($params);

 array(2) {
   [0] =>
   string(1) "1"
   [1] =>
   string(9) "changelog"
 }

I noticed that there is also an "Option" version called InputOption::VALUE_IS_ARRAY, but I did not have success getting it to work. The argument version InputArgument::IS_ARRAY seems to behave as an option anyways, as it does not error if no arguments are specified.

EDIT:

The author's question is seeking "How do i define variable command line options at run time" where my answer is "How do you provide multiple values for a pre-defined option/argument"

like image 20
Fodagus Avatar answered Nov 09 '22 16:11

Fodagus


Here is how to implement this on PHP 7+ using symfony/console ^3.0:

abstract class CommandWithDynamicOptions extends Command {

    /** @var array The list of dynamic options passed to the command */
    protected $dynamicOptions = [];

  /**
   * @inheritdoc
   */
  protected function configure() {
    $this->setName('custom:command');

    $this->setDefinition(new class($this->getDefinition(), $this->dynamicOptions) extends InputDefinition {
      protected $dynamicOptions = [];

      public function __construct(InputDefinition $definition, array &$dynamicOptions) {
        parent::__construct();
        $this->setArguments($definition->getArguments());
        $this->setOptions($definition->getOptions());
        $this->dynamicOptions =& $dynamicOptions;
      }

      public function getOption($name) {
        if (!parent::hasOption($name)) {
          $this->addOption(new InputOption($name, null, InputOption::VALUE_OPTIONAL));
          $this->dynamicOptions[] = $name;
        }
        return parent::getOption($name);
      }

      public function hasOption($name) {
        return TRUE;
      }

    });
  }
}
like image 41
Pierre Buyle Avatar answered Nov 09 '22 17:11

Pierre Buyle