symfony command -- Создать консольную команду php bin/console ...

Симфони обладает мощным интрументом работы с приложением - с помощью консольных команд. Например:

php bin/console cache:clear

Рассмотрим создание своей собственной консольной команды на примере заполнения данными о продуктах интернет-магазина. (Инстанцирование Продукта и создание требуемых связей)

  • Для начала создаём директорию src/AppBundle/Command и в ней класс CreateProductCommand.php:
    <?php
    namespace AppBundle\Command;
    
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    
    class CreateUserCommand extends Command
    {
        protected function configure()
        { ... }
    
        protected function execute(InputInterface $input, OutputInterface $output)
        { ... }
    }
  • Настраиваем конфигурации команды:
    protected function configure()
    {
        $this
            // the name of the command (the part after "bin/console")
            ->setName('app:create-product')
    
            // the short description shown while running "php bin/console list"
            ->setDescription('Creates a new product.')
    
            // the full command description shown when running the command with
            // the "--help" option
            ->setHelp('This command allows you to create a product...')
        ;
    }

    Теперь мы можем запустить команду в консоли так:

    php bin/console app:create-product

    Результата пока не будет, т.к. не описана логика в методе execute()

  • Метод execute() принимает 2 параметра.
    $output - реализует методы OutputInterface(), например, может выводить на экран комментарии по ходу выполнения команды, текст запросов для ввода данных и некоторое другое.
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // метод writeln() отображает строки и добавляет /n в конце каждой
        $output->writeln([
            'Создание продукта...',
            '============',
            '',
        ]);
        // Здесь будет код создания продукта ..
        // метод write() отображает строки без переносов
        $output->write('Создано! ');
    }
  • Можно добавить параметры, вводимые после консольной команды. Добавляем в метод configure():
    ->addArgument('productName', InputArgument::REQUIRED)

    и теперь можем использовать введённый пользователем текст в execute():

    $productName = $input->getArgument('productName');
            if ($productName) {
                $data ['productName'] = $productName;
            }

    Параметр (или все параметры, в порядке объявления) пользователь должен ввести сразу после команды в консоли (можно сделать параметр необязательным, выставив флаг InputArgument::OPTIONAL):

    php bin/console app:create-product my_product_name

    В документации Symfony можно найти и другие возможности рработы консольных команд.

  • Далее просто дописываем всю логику того, что должна делать команда в метод execute().
  • Если вам потребуется запускать консольную команду в коде(не из консоли), например, при запуске приложения, воспользуйтесь компонентом symfony, Console Component

ИТАК

У меня в целом получилось так:

<?php

namespace AppBundle\Command;

use AppBundle\Entity\Category;
use AppBundle\Entity\CategoryProduct;
use AppBundle\Entity\ProductPrice;
use AppBundle\Entity\ProductPhoto;
use AppBundle\Entity\File;
use AppBundle\Entity\Level;
use AppBundle\Entity\User;
use AppBundle\Entity\Product;
use AppBundle\Entity\FieldType;
use AppBundle\Entity\FieldValue;
use DateTime;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CreateProductCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this
            ->setName('app:create-product')
            ->setDescription('Создаём новый Product.')
            ->setHelp('Эта команда генерирует объект Product, а также все связанные с ним объекты.'
                    . 'Данные, заполняющие поля, необходимо ввести вручную в методе'
                    . 'CreateProductCommand::execute() в массив $data перед запуском команды')
            ->addArgument('productName', InputArgument::OPTIONAL)
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln([
            'Создание Продукта...',
            '============',
            '',
        ]);
        
        // Здесь должны храниться данные, загружаемые в объекты. 
        // Для каждого нового значения исправляются вручную
        $data = [
            'level' => ['name' => '1'],
            'user' => ['phone' => '89536554567'],
            'prod' => ['slug' => 'e-456', 'name' => 'Сиреневый утюг e-456', 'description' => 'утюг утюговый'],
            'price' => ['value' => 3500],
            'file' => [
                'name' => 'photo1',
                'size' => 330,
                'mimeType' => 'mime_type',
                'path' => '/img/e-456',
                ],
            'prodPhoto' => ['height' => 75, 'width' => 95],
            'category' => ['slug' => 'irons', 'name' => 'Утюги'],
            'cat_prod' => ['sequence' => 43]
        ];
        
        $dataAttributes = [
         // внутри столько массивов, сколько атрибутов у продукта
            [
                'name' => 'inStockMSK',
                'type' => 'html',
                'label' => 'Наличие товара на складе МСК',
                'value' => 'есть',
            ],
        ];
        // проверяем, если был установлен необязательный атрибут при запуске консольной команды, заменяем имя на указанное пользователем значение
        if ($input->getArgument('productName')) {
            $data['prod']['name'] = $input->getArgument('productName');
        }
        
        $level = new Level();
        $level->setName($data['level']['name']);
        $level->setCreatedAt(new DateTime());
        
        $user = new User();
        $user->setLevel($level);
        $user->setPhone($data['user']['phone']);
        $user->setCreatedAt(new DateTime());
        
        $prod = new Product();
        $prod->setSlug($data['prod']['slug']);
        $prod->setName($data['prod']['name']);
        $prod->setDescription($data['prod']['description']);
        $prod->setCreatedAt(new DateTime());
        
        $price = new ProductPrice();
        $price->setValue($data['price']['value']);
        $price->setLevel($level);
        $price->setCreatedAt(new DateTime());
        $price->setProduct($prod);
        
        $file = new File();
        $file->setName($data['file']['name']);
        $file->setSize($data['file']['size']);
        $file->setMimeType($data['file']['mimeType']);
        $file->setPath($data['file']['path']);
        $file->setCreatedAt(new DateTime());
        
        $prodPhoto = new ProductPhoto();
        $prodPhoto->setFile($file);
        $prodPhoto->setHeight($data['prodPhoto']['height']);
        $prodPhoto->setWidth($data['prodPhoto']['width']);
        $prodPhoto->setProduct($prod);
        $prodPhoto->setCreatedAt(new DateTime());
        
        $category = new Category();
        $category->setName($data['category']['name']);
        $category->setSlug($data['category']['slug']);
        $category->setIsRoot(false);
        $category->setCreatedAt(new DateTime());
        $category->addProduct($prod);
        $prod->addCategory($category);
        
        $cat_prod = new CategoryProduct();
        $cat_prod->setCategory($category);
        $cat_prod->setProduct($prod);
        $cat_prod->setSequence($data['cat_prod']['sequence']);
        $cat_prod->setCreatedAt(new DateTime());
        
        // Добавляем атрибуты товара (количество может меняться)
        $em = $this->getContainer()
                ->get('doctrine')
                ->getManager();
        
        foreach ($dataAttributes as $data) {
            $type = new FieldType();
            $type->setName($data['name']);
            $type->setType($data['type']);
            $type->setLabel($data['label']);
            $type->setCategory($category);
            $type->setCreatedAt(new DateTime());

            $value = new FieldValue();
            $value->setValue($data['value']);
            $value->setProduct($prod);
            $value->setCreatedAt(new DateTime());
            $value->setFieldType($type);
            
            $em->persist($value);
            $em->persist($type);
        }
        
        // Сохраняем всё в БД
        $em->persist($level);
        $em->persist($user);
        $em->persist($prod);
        $em->persist($price);
        $em->persist($prodPhoto);
        $em->persist($file);
        $em->persist($category);
        $em->persist($cat_prod);
        
        $em->flush();
        
        $output->writeln($input->getArgument('productName') . ' cоздан!');
    }

Источники

https://symfony.com/doc/current/console....