簡體   English   中英

在沒有 Symfony 框架包的情況下,如何使用依賴注入的 Symfony 控制台?

[英]how do I use Symfony console with dependency injection, without the Symfony framework bundle?

我有一個命令行應用程序,到目前為止它使用 Symfony 依賴注入組件。 我現在發現我想添加命令行選項並改進 output 的格式,而 Symfony 控制台組件似乎是一個不錯的選擇。

但是,我無法理解如何讓我的 Symfony 控制台命令類接收容器 object。

我找到的文檔使用了 ContainerAwareCommand class,但那是來自 FrameworkBundle——添加到純 CLI 應用程序似乎需要大量開銷,因為它需要進一步的捆綁,例如路由、http、配置、緩存等,這些都與我無關。

(現有的 SO 問題How can i inject dependencies to Symfony Console commands?也假定 FrameworkBundle,BTW。)

我在這里創建了一個測試存儲庫,其中包含一個說明問題的基本命令: https://github.com/joachim-n/console-with-di

Symfony 3/4/5 路

自 2018 年和Symfony 3.4+ DI 功能以來,您可以將命令用作服務

感謝@TravisCarden,您可以在這里找到工作演示

簡而言之:

1. 應用內核

<?php

# app/Kernel.php

namespace App;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class AppKernel extends Kernel
{
    public function registerBundles(): array
    {
        return [];
    }

    public function registerContainerConfiguration(LoaderInterface $loader): void
    {
        $loader->load(__DIR__.'/../config/services.yml');
    }

    protected function build(ContainerBuilder $containerBuilder): void
    {
        $containerBuilder->addCompilerPass($this->createCollectingCompilerPass());
    }

    private function createCollectingCompilerPass(): CompilerPassInterface
    {
        return new class implements CompilerPassInterface
        {
            public function process(ContainerBuilder $containerBuilder)
            {
                $applicationDefinition = $containerBuilder->findDefinition(Application::class);

                foreach ($containerBuilder->getDefinitions() as $definition) {
                    if (! is_a($definition->getClass(), Command::class, true)) {
                        continue;
                    }

                    $applicationDefinition->addMethodCall('add', [new Reference($definition->getClass())]);
                }
            }
        };
    }
}

2. 服務

# config/services.yml

services:
    _defaults:
        autowire: true

    App\:
        resource: '../app'

    Symfony\Component\Console\Application:
        public: true

3.bin文件

# index.php

require_once __DIR__ . '/vendor/autoload.php';

use Symfony\Component\Console\Application;

$kernel = new AppKernel;
$kernel->boot();

$container = $kernel->getContainer();
$application = $container->get(Application::class)
$application->run();

運行

php index.php

如果你對更詳細的解釋感興趣,我寫了一篇文章為什么你應該結合 Symfony 控制台和依賴注入

是的,不需要整個框架。 在您的情況下,首先您需要創建一種入口腳本。 類似的東西:

<?php

require 'just/set/your/own/path/to/vendor/autoload.php';

use Symfony\Component\Console\Application;
use Symfony\Component\DependencyInjection\ContainerBuilder;

$container = new ContainerBuilder();
$container
    ->register('your_console_command', 'Acme\Command\YourConsoleCommand')
    ->addMethodCall('setContainer', [new Reference('service_container')]);
$container->compile();

$application = new Application();
$application->add($container->get('your_console_command'));
$application->run();

在這個例子中,我們創建容器,然后將命令注冊為服務,向命令添加一個依賴項(在我們的例子中是整個容器——但顯然你可以創建另一個依賴項並注入它)並編譯容器。 然后我們只需創建應用程序,將命令實例添加到應用程序並運行它。

當然,您可以將容器的所有配置保留在yamlxml ,甚至可以使用 PHP 格式。

四年后,但適用於尋找類似解決方案的人。 我有一個看起來相似的場景,並通過依賴注入實現了我自己的樣板,准備好 go 用於獨立的 symfony 控制台應用程序,支持命令和服務的自動連接和自動配置。

composer create-project coral-media/crune crune

接收容器的示例命令。 源代碼可在Github 獲取

快樂編碼!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM