Como criar um comando personalizado no Magento 2
Tags: php, magento2, braziliandevs, tutorial
Published: 2022-03-10 11:56:43

## Contextualizando

### O que é um CLI?

A **CLI** (*Command Line Interface*, ou Interface de Linha de Comando) é um ambiente onde é possível interagir através do terminal para a execução de tarefas específicas pelas linhas de comando digitados pelo usuário, e após a execução da tarefa, exibirá o retorno do processo no próprio terminal.
Cada linha de comando do terminal é responsável pela execução de uma funcionalidade específica, podendo definir o valor de alguma configuração ou a realização de uma tarefa.

---

## Código para criar um comando

Saiba mais sobre definir valores no construtor de com o type no *post* "[Como definir valores específicos dos argumentos do construtor no Magento 2 utilizando *type*](https://dev.to/santanaluc94/como-definir-valores-especificos-dos-argumentos-do-construtor-no-magento-2-utilizando-type-7e1)".

### di.xml

Configurações *Type* descrevem o tipo de uma dependência do construtor de uma determinada classe e qual valor instanciar. Para declarar um comando é necessário injetar na classe `\Magento\Framework\Console\CommandListInterface` via configuração *type,* dentro do arquivo `di.xml`, seguindo a estruturas de pastas `\{Vendor}\{Module}\etc\{area}\di.xml`.

A configuração que será injetada deve ser do tipo `object`, referenciando o caminho da classe onde terá as definições do comando. 

```xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <type name="Magento\Framework\Console\CommandList">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="{comandName}" xsi:type="object">{Vendor}\{Module}\Console\{Directory}\{ConsoleClass}</item>
            </argument>
        </arguments>
    </type>
</config>
```

### Console

A classe de Console deverá seguir a estrutura de pastas `\{Vendor}\{Module}\Console\{Directory}\{ConsoleClass}` e estender a classe `\Symfony\Component\Console\Command\Command`. Esta classe deverá possuir o método protegido `configure()`, que será utilizado para definir o nome, a descrição, os argumentos e outras caracterísiticas que o comando possuirá. A classe também possuirá o método protegido `execute()`, que será o utilizado para executar as tarefas quando o comando for chamado através do terminal.

É possível, mas não obrigatório, implementar o método `interact(\Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output)`, este método é executado antes da validação, ou seja, é o único lugar onde o comando pode interativamente perguntar por valores dos argumentos que não foram passados no comando do terminal.

```php
<?php

namespace {Vendor}\{Module}\Console\{Directory};

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputDefinition;

class {ConsoleClass} extends Command
{
    protected function configure(): void
    {
        // Set the name of the comand that will be used in the prompt
        $this->setName('{section}:{command}');

        // Set the description for the comand
        $this->setDescription('{Console description}');

        // Sets an array of argument and option instances
        $this->setDefinition({[]});

        // Add an arguments to command
        $this->addArgument('{argumentName}');

        // Add an option to command
        $this->addOption('{optionName}');

        // Sets the process title of the command. This feature should be used only when creating a long process command
        $this->setProcessTitle('{titleProcess}');

        // Sets whether or not the command should be hidden from the list of commands
        $this->setHidden({true/false});

        // Sets the help for the command
        $this->setHelp('{Text to help}');

        // Sets the aliases for the command
        $this->setAliases({['{aliasName}']});

        // Add a command usage example
        $this->addUsage('{The usage}');

        parent::configure();
    }

    protected function execute(
        InputInterface $input,
        OutputInterface $output
    ): void {
        // Code to execute when running the command
    }

    protected function interact(
        InputInterface $input,
        OutputInterface $output
    ): void {
        // Code to execute before input
    }
}
```

Ao definir o nome do comando e a tarefa que será executada ao chamar o comando pelo terminal, basta testar o comando no terminal, após habilitar as alterações (conforme abaixo).

```bash
bin/magento {section}:{command}
```

---

## Finalização

> Valores entre chaves (`{test}`) devem ser alterados na implementação do código.

### Habilitando as alterações

Apague os arquivos que são gerados na compilação do Magento e execute o comando PHP para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (*proxys*, *interceptors*, etc) e para limpar todos os caches de armazenamento em cache do processos.

```bash
rm -rf var/generation/
rm -rf generated/
php bin/magento setup:di:compile
php bin/magento cache:clean
php bin/magento flush
```

### Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

```
- app/
  - code/
    - {Vendor}/
      - {Module}/
        - etc/
          - module.xml
          - di.xml
        - Console/
          - {Directory}/
            - {ConsoleClass}.php
        - registration.php
        - composer.json
```