2

tl;dr:我有一个 Symfony 服务配置,它将默认字符串值绑定到命名参数,我想在控制台进程中使用命令行选项值覆盖它。

我正在开发一个 Composer 库(php-tuf/composer-stager),它为类提供公共接口和一个为它们提供 shell 接口的 Symfony 控制台应用程序。对于代码 API,我想将默认(字符串)值绑定到一些服务参数,以便客户端不必在每次调用我的域服务时都包含参数,但他们仍然可以在自己的服务配置中覆盖默认值。

但是在我自己的控制台应用程序中,我希望能够根据用户可能提供的命令行选项覆盖这些默认值。例如,我希望有一个$string默认值lorem,但我希望我的控制台使用一个选项覆盖默认值,例如--string=ipsum. 但是当控制台应用程序处理用户输入时,我找不到任何地方来更改容器中参数的值。这是一个简化的代码示例:

<?php
// bin/example.php, my console command front script

$containerBuilder = new ContainerBuilder();
$loader = new YamlFileLoader($containerBuilder, new FileLocator());
$loader->load(__DIR__ . '/../config/services.yml');

// This is the last chance to override defaults before the container
// gets compiled, but I'm reluctant to do so because I would have
// to parse the command line options myself, which would be ugly if
// not unwise.

$containerBuilder->compile();
$application = $containerBuilder->get(Application::class);
return $application->run();
# config/services.yml

services:
    _defaults:
        bind:
            $string: lorem
            
    # These classes constitute my public interface, 
    # and they take the $string parameter.
    My\App\Domain\:
        resource: '../src/Domain/*'

    # These are the Console commands. They need to
    # change the value of $string before it gets
    # injected into the domain classes above.
    My\App\Console\Commands\:
        resource: '../src/Console/Commands/*'
<?php
// src/Domain/Example.php

// By the time this class is instantiated, the container has already been
// compiled, and it's received the $string variable from the services default.
class Example
{
    public function __construct(string $string)
    {
        $this->string = $string;
    }

    public function printString()
    {
        print $this->string;
    }
}
// src/Console/Application.php

// My Applilcation class is the first place (I think) I have access to
// console command input, but the container has already been compiled and
// services injected into my domain objects by the time it's loaded.
final class Application extends \Symfony\Component\Console\Application {}
<?php
// src/Console/Command/ExampleCommand.php

class ExampleCommand
{
    public function __construct(Example $example)
    {
        // At this point the Example class has ALREADY had the
        // $string value injected from the services config.
        $this->example = $example;
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        // ...but I don't get access to the '--override' option until here.
        $override = $input->getOption('override');

        // I'm not WILLING to take $string as a method parameter like this:
        $this->example->printString($override);
        
        // I don't really WANT to add a setter method to the domain (Example)
        // class: It would be too easy for a developer to forget to do this in
        // new commands and introduce bugs.
        $this->example->setString($override);
        $this->example->printString();
        
        // I want the Example class to have gotten the overridden value in
        // the first place so I can call it without every class having to
        // worry about it:
        $this->example->printString();
    }
}

有任何想法吗?

您可以在https://github.com/php-tuf/composer-stager/tree/v0.1.0查看我当前的代码库。

注意:我的应用程序此时需要支持 Symfony 4 和 5。

4

0 回答 0