Подтвердить что ты не робот

Переопределить команды консоли symfony2?

Можно ли переопределить команды symfony2 app/console? Например, в FOS UserBundle я хотел бы добавить еще несколько полей, которые он запрашивает, когда он создает пользователя с консолью, создавая пользовательскую команду. Возможно ли это, или мне нужно создать собственную консольную команду в моем собственном пакете?

4b9b3361

Ответ 1

Весь процесс добавления большего количества полей в команду:

1. В вашем классе AcmeDemoBundle вы должны установить FOSUser как родительский:

<?php

namespace Acme\UserBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class AcmeUserBundle extends Bundle
{
    public function getParent()
    {
        return 'FOSUserBundle';
    }
}

2. Когда вы сделаете это, вы сможете воссоздать CreateUserCommand в своем комплекте:

<?php

namespace Acme\UserBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use FOS\UserBundle\Model\User;

/**
 * @author Matthieu Bontemps <[email protected]>
 * @author Thibault Duplessis <[email protected]>
 * @author Luis Cordova <[email protected]>
 */
class CreateUserCommand extends ContainerAwareCommand
{
    /**
     * @see Command
     */
    protected function configure()
    {
        $this
            ->setName('fos:user:create')
            ->setDescription('Create a user.')
            ->setDefinition(array(
                new InputArgument('username', InputArgument::REQUIRED, 'The username'),
                new InputArgument('email', InputArgument::REQUIRED, 'The email'),
                new InputArgument('password', InputArgument::REQUIRED, 'The password'),
                new InputArgument('name', InputArgument::REQUIRED, 'The name'),
                new InputOption('super-admin', null, InputOption::VALUE_NONE, 'Set the user as super admin'),
                new InputOption('inactive', null, InputOption::VALUE_NONE, 'Set the user as inactive'),
            ))
            ->setHelp(<<<EOT
The <info>fos:user:create</info> command creates a user:

  <info>php app/console fos:user:create matthieu</info>

This interactive shell will ask you for an email and then a password.

You can alternatively specify the email and password as the second and third arguments:

  <info>php app/console fos:user:create matthieu [email protected] mypassword</info>

You can create a super admin via the super-admin flag:

  <info>php app/console fos:user:create admin --super-admin</info>

You can create an inactive user (will not be able to log in):

  <info>php app/console fos:user:create thibault --inactive</info>

EOT
            );
    }

    /**
     * @see Command
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $username   = $input->getArgument('username');
        $email      = $input->getArgument('email');
        $password   = $input->getArgument('password');
        $name       = $input->getArgument('name');
        $inactive   = $input->getOption('inactive');
        $superadmin = $input->getOption('super-admin');

        $manipulator = $this->getContainer()->get('acme.util.user_manipulator');
        $manipulator->create($username, $password, $email, $name, !$inactive, $superadmin);

        $output->writeln(sprintf('Created user <comment>%s</comment>', $username));
    }

    /**
     * @see Command
     */
    protected function interact(InputInterface $input, OutputInterface $output)
    {
        if (!$input->getArgument('username')) {
            $username = $this->getHelper('dialog')->askAndValidate(
                $output,
                'Please choose a username:',
                function($username) {
                    if (empty($username)) {
                        throw new \Exception('Username can not be empty');
                    }

                    return $username;
                }
            );
            $input->setArgument('username', $username);
        }

        if (!$input->getArgument('email')) {
            $email = $this->getHelper('dialog')->askAndValidate(
                $output,
                'Please choose an email:',
                function($email) {
                    if (empty($email)) {
                        throw new \Exception('Email can not be empty');
                    }

                    return $email;
                }
            );
            $input->setArgument('email', $email);
        }

        if (!$input->getArgument('password')) {
            $password = $this->getHelper('dialog')->askAndValidate(
                $output,
                'Please choose a password:',
                function($password) {
                    if (empty($password)) {
                        throw new \Exception('Password can not be empty');
                    }

                    return $password;
                }
            );
            $input->setArgument('password', $password);
        }

        if (!$input->getArgument('name')) {
            $name = $this->getHelper('dialog')->askAndValidate(
                $output,
                'Please choose a name:',
                function($name) {
                    if (empty($name)) {
                        throw new \Exception('Name can not be empty');
                    }

                    return $name;
                }
            );
            $input->setArgument('name', $name);
        }
    }
}

Примечание. Я добавил новый входной аргумент с именем name и внутри команды. Я использую службу acme.util.user_manipulator вместо исходного. Там я буду обрабатывать также имя пользователя.

3. Создайте собственный UserManipulator:

<?php

namespace Acme\UserBundle\Util;

use FOS\UserBundle\Model\UserManagerInterface;

/**
 * Executes some manipulations on the users
 *
 * @author Christophe Coevoet <[email protected]>
 * @author Luis Cordova <[email protected]>
 */
class UserManipulator
{
    /**
     * User manager
     *
     * @var UserManagerInterface
     */
    private $userManager;

    public function __construct(UserManagerInterface $userManager)
    {
        $this->userManager = $userManager;
    }

    /**
     * Creates a user and returns it.
     *
     * @param string  $username
     * @param string  $password
     * @param string  $email
     * @param string  $name
     * @param Boolean $active
     * @param Boolean $superadmin
     *
     * @return \FOS\UserBundle\Model\UserInterface
     */
    public function create($username, $password, $email, $name, $active, $superadmin)
    {
        $user = $this->userManager->createUser();
        $user->setUsername($username);
        $user->setEmail($email);
        $user->setName($name);
        $user->setPlainPassword($password);
        $user->setEnabled((Boolean)$active);
        $user->setSuperAdmin((Boolean)$superadmin);
        $this->userManager->updateUser($user);

        return $user;
    }
}

В этом классе мне нужна только функция create, поэтому остальные команды, такие как promotion, demote.., не знают о ваших новых пользовательских свойствах, поэтому мне не нужно создавать CompilerPass для переопределения всей службы.

4. Наконец, определите эту новую службу UserManipulator в каталоге Resources/config и добавьте ее в расширение DependencyInjection:

services:
    acme.util.user_manipulator:
        class:      Acme\UserBundle\Util\UserManipulator
        arguments:  [@fos_user.user_manager]

Готово!!!

Ответ 2

Вы можете переопределить команды консоли, если вы создаете (или уже имеете) свой собственный пакет, который является дочерним элементом этого пакета (см. Наследование пачек). Затем, поместив класс в ваш пакет с тем же именем/именем, что и исходная команда, вы его эффективно отмените.

Так, например, чтобы переопределить FOS/UserBundle/Command/CreateUserCommand.php, создайте MyCompany/UserBundle/Command/CreateUserCommand, где MyCompanyUserBundle имеет FOSUserBundle в качестве родителя.

Ваш класс команд может расширить класс команд FOS, чтобы повторно использовать (бит) его. Однако, посмотрев на FOS CreateUserCommand, я думаю, вам нужно будет переопределить все методы, чтобы добавить дополнительные поля ввода, и в этом случае нет никакой пользы для этого. Конечно, это также означает, что вы можете просто создать свою собственную команду в любом комплекте, но, на мой взгляд, лучше сохранить настройку FOSUserBundle в дочернем комплекте.

Ответ 3

Symfony 4 удалил наследование пакета, но вы все равно можете переопределить команды, украсив их. Это чище и не требует связки. Просто добавьте это в services.yaml:

services:
    App\Command\MyCustomCommand:
        decorates: command_you_want_to_override

Обратите внимание, что command_you_want_to_override является именем службы. Для более старых команд pre-Symfony 3.3 это будет что-то в нижнем регистре с точками и подчеркиванием (например, doctrine_migrations.diff_command), для более новых это будет имя класса. Вы можете найти это имя, проверив его конфигурацию службы комплектов или выполнив поиск по выводу debug:container. В Linux или macOS это будет:

php bin/console debug:container | grep Command

Ответ 4

В Symfony (3.3) вы можете переопределить команды консоли, следуя этим ссылкам. https://symfony.com/doc/current/console/calling_commands.html и опции https://symfony.com/doc/current/console/input.html

Код из документа symfony:

use Symfony\Component\Console\Input\ArrayInput;
// ...

protected function execute(InputInterface $input, OutputInterface $output)
{
    $command = $this->getApplication()->find('demo:greet');

    $arguments = array(
        'command' => 'demo:greet',
        'name'    => 'Fabien',
        '--yell'  => true,
    );

    $greetInput = new ArrayInput($arguments);
    $returnCode = $command->run($greetInput, $output);

    // ...
}