Weitere Consolen Befehle zu Symfony 4 hinzufügen

von CodeKanal @codekanal

Standardmäßig hat Symfony den Befehl bin/console. Aus Gründen der Übersichtlichkeit kann es sinnvoll sein, eigene weitere Befehle von diesen System Befehlen zu trennen. Hier stellen wir eine Möglichkeit vor, dieses schnell und unkompliziert zu implementieren.

Zusammenfassung:

Aufbauend auf bin/console erstellen wir bin/cli: Der Unterschied ist, dass wir \App\CliApplication() verwenden, anstatt \Symfony\Bundle\FrameworkBundle\Console\Application

Die Datei bin/cli:

#!/usr/bin/env php
<?php

use App\Kernel;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;

set_time_limit(0);

require dirname(__DIR__).'/vendor/autoload.php';


$input = new ArgvInput();
if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) {
    putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
}

if ($input->hasParameterOption('--no-debug', true)) {
    putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
}

require dirname(__DIR__).'/config/bootstrap.php';

if ($_SERVER['APP_DEBUG']) {
    umask(0000);

    if (class_exists(Debug::class)) {
        Debug::enable();
    }
}

$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$application = new \App\CliApplication($kernel);

$application->run($input);

Die Datei src/cliApplication.php erweitert die Symfony Console\Application und bestimmt das Laden unserer eigenen Befehle:

<?php
namespace App;

use Symfony\Bundle\FrameworkBundle\Console\Application as BaseApplication;
use Symfony\Component\HttpKernel\KernelInterface;

class CliApplication extends BaseApplication
{
    private $commandsRegistered = false;

    public function __construct(KernelInterface $kernel)
    {
        parent::__construct($kernel);

        $this->setName("myCliTool");
        $this->setVersion("1.0.0");
    }

    /**
     * register commands from CliCommand Namespace
     */
    protected function registerCommands()
    {
        if ($this->commandsRegistered) {
            return;
        }

        $this->commandsRegistered = true;

        $this->getKernel()->boot();
        $this->setCommandLoader($this->getKernel()->getContainer()->get('cli.command_loader'));
    }
}


In src/Kernel.php müssen wir einen CompilerPass hinzufügen (Mehr dazu unter How to Work with Compiler Passes). Dazu implementieren wir das CompilerPassInterface und ergänzen die Methode process():

<?php

namespace App;

// ...
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;


class Kernel extends BaseKernel implements CompilerPassInterface
{

    // ...

    public function process(ContainerBuilder $container)
    {
        $cliCommandsLoader = new AddConsoleCommandPass('cli.command_loader', 'cli.command');
        $cliCommandsLoader->process($container);
    }
}


Als letzten Schritt müssen wir noch in config/services.yaml unsere eigenen Befehle mit einem Tag versehen:

services:
    # ...

    # Load Commands from src/CliCommand
    App\CliCommand\:
        resource: '../src/CliCommand'
        tags: ['cli.command']

Fertig.

Ein Aufruf von bin/cli zeigt nun etwa folgendes an:

myCliTool 1.0.0 (env: dev, debug: true)

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -e, --env=ENV         The Environment name. [default: "dev"]
      --no-debug        Switches off debug mode.
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug


Available commands:
  help        Displays help for a command
  list        Lists commands
  myFirstCmd  First sample command
  mySndCmd    Second sample command


Wir erhalten damit alle Funktionen von Symfony und haben trotzdem eine gute Übersicht über unsere eigenen Befehle.