Как определять команды, как сервисы

Если вы используете конфигурацию services.yaml по умолчанию, то ваши классы команд уже зарегистрированы, как сервисы. Отлично! Это рекомендованная установка.

Note

Вы также можете вручную зарегистрировать вашу команду, как сервис, сконфигурировав сервис и тегировав его с помощью console.command.

В любом случае, если ваш класс расширяет ContainerAwareCommand, то вы можете получить доступ к публичным сервисам через $this->getContainer()->get('SERVICE_ID').

Но если ваш класс зарегистрирован, как сервис, вы можете вместо этого получить доступ к сервисам, используя нормальное внедрение зависимости.

Например, представьте, что вы хотите записать лог чего-либо изнутри вашей команды:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
namespace App\Command;

use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class SunshineCommand extends Command
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;

        // вы *должны* вызвать родительский конструктор
        parent::__construct();
    }

    protected function configure()
    {
        $this
            ->setName('app:sunshine')
            ->setDescription('Good morning!');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->logger->info('Waking up the sun');
        // ...
    }
}

Если вы используете конфигурацию services.yaml по умолчанию, то класс команды автоматически будет зарегистрирован, как сервис, и передан аргументу $logger (благодаря автомонтированию). Другими словами, просто создав этот класс, всё работает! Вы можете вызвать команду app:sunshine и начать вести запись логов.

Caution

У вас есть достут к серверам configure(). Однако, если ваша команда не ленивая, попробуйте избегать любой работы (например, запросы в БД), так как этот код будет выполнен, даже если вы используете консоль для выполнения другой комнады.

Ленивая загрузка

Чтобы сделать вашу команду лениво загружаемой, определите её статичное свойство $defaultName:

1
2
3
4
5
6
class SunshineCommand extends Command
{
    protected static $defaultName = 'app:sunshine';

    // ...
}

Или установите атрибут command в теге console.command в вашем определении сервиса:

  • YAML
    1
    2
    3
    4
    5
    6
    # config/services.yaml
    services:
        App\Command\SunshineCommand:
            tags:
                - { name: 'console.command', command: 'app:sunshine' }
            # ...
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Command\SunshineCommand">
                 <tag name="console.command" command="app:sunshine" />
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    // config/services.php
    use App\Command\SunshineCommand;
    //...
    
    $container
        ->register(SunshineCommand::class)
        ->addTag('console.command', array('command' => 'app:sunshine'))
    ;
    

Вот и всё. Так или иначе, SunshineCommand будет инстанциирована только тогда, когда команда app:sunshine будет действительно вызвана.

Note

Вам не нужно вызывать setName() для конфигуриации команды, если она ленивая.

Caution

Вызов команды list инстанциирует все команды, включая ленивые.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.