Symfony Console - 覆盖默认选项

5
我正在使用Symfony Console构建一个CLI应用程序。该应用程序需要执行一些简单的软件包管理操作来管理插件。因此,我需要一个命令选项,名为--version,快捷方式为-v,但似乎不可能,因为--version已被保留用于应用程序版本,-v已被保留用于默认详细程度设置。
如何禁用默认选项或覆盖此子命令的默认选项?

弹出的错误消息如下:

[Symfony\Component\Console\Exception\LogicException] 已经存在名为“version”的选项。


默认值在Console\Application::getDefaultInputDefinition中定义,所以我想你可以创建自己的Application类并进行覆盖。Application::doRun()实际上有一个硬编码检查--version,所以你也需要进行覆盖。最好选择一个不同的选项名称,比如--package-version或其他名称,这样会更容易些。 - Cerad
是的,我也考虑过--package-version,但说实话,谁想打那么多字呢? ;) 我想我会为此开一个问题。 - Moritz Friedrich
什么问题?按设计,如果你想要不同的选项,那就覆盖它。很容易。 - Cerad
1
如果Application::doRun()有一个硬编码的参数检查,那么对我来说似乎有些不对。CLI应用程序框架不应该强制要求我使用某个命令选项。只需注册一个选项以覆盖任何默认值即可。 - Moritz Friedrich
我真的建议使用另一个选项名称,比如--package-version。你可以尝试覆盖Application类并将bin/console复制到一个新命令中,该命令加载此应用程序,但在那之后你仍然会遇到很多困难。Symfony有一个受保护的getDefaultInputDefinition()函数,您可以重写并删除version选项,但doRun()命令中有一个硬编码检查version的内容,您必须在删除它的同时复制现有代码。 - Jason Roman
1个回答

3

这里有一个可行的解决方案,但我不建议使用它。我建议你只需使用--package-version或其他某种选项来执行命令,因为这需要额外的工作量,并且不适用于未来Symfony更新。

第一件事是将bin/目录中的console命令复制到一个新命令中,并将use语句更改为你自己扩展的应用程序:

bin/alt_console:

// use Symfony\Bundle\FrameworkBundle\Console\Application;
use AppBundle\Console\Application;

然后创建一个新的Application类来扩展现有的Symfony应用程序,像这样:

应用程序:

namespace AppBundle\Console;

use AppBundle\Command\YourCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class TestApplication extends Application
{
    const NAME = 'Alternative Application';
    const VERSION = '1.0';

    // these are normally private, but must now be protected as they exist in doRun()
    protected $command;
    protected $defaultCommand;
    protected $dispatcher;
    protected $runningCommand;

    /**
     * {@inheritdoc}
     */
    public function __construct()
    {
        parent::__construct(static::NAME, static::VERSION);

        // manually add the commands you want to be handled by this
        $this->add(new YourCommand());
    }

    /**
     * {@inheritdoc}
     */
    public function doRun(InputInterface $input, OutputInterface $output)
    {
        /* remove these lines
        if (true === $input->hasParameterOption(array('--version', '-V'), true)) {
            $output->writeln($this->getLongVersion());

            return 0;
        }
        */

        // copy the rest of the doRun() function as it 
        // exists in the base Application class
        // ...
    }

    /**
     * {@inheritdoc}
     *
     * Return everything from the default input definition except the 'version' option
     */
    protected function getDefaultInputDefinition()
    {
        $definition  = [];

        $defaultDefinition = parent::getDefaultInputDefinition();

        foreach ($defaultDefinition->getOptions() as $option) {
            if ($option->getName() !== 'version') {
                $definition[] = $option;
            }
        }

        foreach ($defaultDefinition->getArguments() as $argument) {
            $definition[] = $argument;
        }

        return new InputDefinition($definition);
    }
}

现在,您可以使用自己的--version选项将应用程序添加进去:
namespace AppBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class YourCommand extends ContainerAwareCommand
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName('your:command')
            ->addOption('--version', '-V', InputOption::VALUE_NONE, 'okay')
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if ($input->hasOption('version')) {
            // do something
        }
    }
}

然后,您可以通过以下方式调用您的命令:

php bin/console your:command
php bin/console your:comand --version

请注意,我不建议这么做。这样做只是为了节省几个按键的时间,但实际上需要付出很多额外的工作量。此外,如果 bin/console 或者 Symfony\Component\Console\Application 在以后发生变化,那么您就必须手动更新这些文件,因为您已经覆盖了它们。

非常感谢您的详细回答,但是您是对的,我会使用另一个参数名称。我最初发布这个问题是因为我认为我只是做错了什么。 - Moritz Friedrich
没问题,这绝对是一个有趣的实验。 - Jason Roman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接