How to use Symfony console with dependency injection, without Symfony module bundle?

I have a command line application that still uses the Symfony Dependency Injection component. Now I've found that I want to add command line options and improve output formatting, and the Symfony console component looks like a good choice for that.

However, I can't figure out how to get my Symfony console command classes to get the container object.

The documentation I found uses the ContainerAwareCommand class, but this is from FrameworkBundle, which is a huge amount of overhead to add to a pure CLI program as it requires additional packages like routing, http, config, cache, etc. none of which has anything to do with me.

(Existing SO question How can I add dependencies to Symfony Console commands? Also accepts FrameworkBundle, BTW.)

Here I created a test repository with a basic command that illustrates the problem: https://github.com/joachim-n/console-with-di

+3


source to share


2 answers


Yes, the whole structure is not required. In your case, you first need to create a script entry. Something like that:

<?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();

      



In this example we create a container, then we register the command as a service, add a dependency to the command (the whole container in our case - but obviously you can create another dependency and inject it) and compile the container.Then we just create the application, add the command instance into the application and launch it.

Of course, you can store all the configuration container yaml

, or xml

even using the PHP format.

0


source


Since 2018 and Symfony 3.4+ DI features , you can use commands as services.

In short:

1. Application core

<?php

# app/Kernel.php

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class AppKernel extends Kernel
{
    /**
     * In more complex app, add bundles here
     */
    public function registerBundles(): array
    {
        return [];
    }

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

    /**
     * Add all Commands to Application
     */
    protected function build(ContainerBuilder $containerBuilder): void
    {
        $applicationDefinition = $containerBuilder->getDefinition(
        Application::class
        );

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

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

      

2. Services

# config/services.yml

services:
    _defaults:
        autowire: true

    App\:
        resource: '../app'

      



3. Bean file

# 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();

      

Run it

php index.php

      


If you are interested in a more detailed explanation, I wrote a post Why you should combine Symfony Console and Dependency Injection .

0


source







All Articles