假设我有一个命令只做一个人:
class PlainTextHelloWorldCommand extends Command
{
protected function configure()
{
$this
->setName('text:hello')
->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$receiver = $input->getArgument('receiver');
$output->writeln("Hello {$receiver}!");
}
}
另一个命令现在也需要receiver
参数:
class HtmlHelloCommand extends Command
{
/**
*
* @throws InvalidArgumentException
*/
protected function configure()
{
$this
->setName('html:hello')
->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$receiver = $input->getArgument('receiver');
$output->writeln("<html><h1>Hello {$receiver}!</h1></html>");
}
}
我现在正在思考如何不重复自己。
我想分享逻辑来添加参数并解析输入,以便它在一个地方。
我知道我可以创建一个“ReceiverAwareCommand”,但如果我获得更多参数会发生什么?
我不希望SendEmailCommand扩展MessageAwareGreeterCommand扩展receiverAwareCommand ...`。这条道路似乎导致地狱,因此我喜欢避免继承。
此外,我的示例是简化的,因为两个示例命令基本相同。情况不一定如此。此外,我有大约10个参数,而每个命令最多可能需要4个参数。
我只想在没有自己的情况下在需要时设置这些参数。
我正在思考Decorator模式的方向,但在这种情况下我对如何设置它们感到困惑,所以感觉错误。
因此我想知道:如何实现这一目标?
答案 0 :(得分:1)
作为symfony 4。
我创建了一个名为Configure的类,并在其中添加了3个静态函数。
namespace MyApp\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\{InputInterface, InputArgument, InputOption};
class Configure {
static function arguments(Command $command, array $arguments) {
foreach($arguments as $argument) {
// Include here all of your re-useable arguments.
switch($argument) {
case 'arg1':
$command->addArgument('arg1', InputArgument::REQUIRED, 'Description.');
break;
case 'arg2':
$command->addArgument('arg2', InputArgument::REQUIRED, 'Description');
break;
// ...
// Add more here.
}
}
}
static function options(Command $command, array $options) {
foreach($options as $option) {
// Include here all of your re-usable options.
switch($option) {
case 'opt1':
$command->addOption('opt1', NULL, InputOption::VALUE_REQUIRED, '.');
break;
case 'opt2':
$command->addOption('opt2', NULL, InputOption::VALUE_REQUIRED, '.');
break;
// ...
// Add more here.
}
}
}
static function validate(InputInterface $input) {
// Include here all of your default validations.
if ($input->getOption('opt2') && !$input->getOption('opt1'))
throw new \Exception('You must send --opt1 when sending --opt2');
// ...
// Add more here.
}
}
在命令中,我选择要重新使用的参数/选项。
namespace MyApp\Commands;
use Symfony\Component\Console\Input\{InputInterface, InputArgument, InputOption};
use Symfony\Component\Console\{Command\Command, Output\OutputInterface};
class MyCommand extends Command {
protected static $defaultName = 'my:command';
protected function configure() {
// Here you set the arguments/options that are unique to this
// command.
$this
->setDescription('Description.')
->addOption('only_here', 'o', NULL, 'Description.');
// You can pick and choose which of your default arguments/option
// should be included in this command.
Configure::arguments($this, ['arg1', 'arg2']);
Configure::options($this, ['opt2']);
}
protected function execute(InputInterface $input, OutputInterface $output) {
Configure::validate($input);
// ...
// My stuff here.
}
}
答案 1 :(得分:0)
(我知道你不想继承,但我找不到更好的主意)
您可以通过添加方法BaseCommand
定义add…Argument
来定义所有参数:
class BaseCommand extends Command
{
static $format = '%s';
protected function configure()
{
parent::configure();
// Define a fake command (IIRC Symfony throws an error without this).
$this
->setName('command:base')
->setDescription('Base command')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output); //initialize parent class method
$receiver = $input->getArgument('receiver');
$output->writeln(sprintf($this::$format, $receiver));
}
/***** Define arguments *****/
protected function addReceiverArgument()
{
$this
->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?')
;
return $this;
}
protected function addOtherArgument()
{
$this
->addArgument('other', InputArgument::REQUIRED, 'Other argument')
;
return $this;
}
}
然后您可以在子类中重用这些方法:
class PlainTextHelloWorldCommand extends BaseCommand
{
protected function configure()
{
parent::configure();
$this
->setName('text:hello');
$this
->addReceiverArgument()
;
}
}
如果另一个命令需要2个参数,那很简单:
class HtmlHelloCommand extends BaseCommand
{
// Change the output formatting.
static $format = '<html><h1>Hello %s!</h1></html>';
protected function configure()
{
parent::configure();
$this
->setName('html:hello')
;
$this
->addReceiverArgument()
->addOtherArgument()
;
}
}
然后你可以调用命令:
$ php app/console text:hello aaa
Hello aaa!
$ php app/console html:hello aaa
[Symfony\Component\Console\Exception\RuntimeException]
Not enough arguments (missing: "other").
$ php app/console html:hello aaa bbb
<html><h1>Hello aaa!</h1></html>