Forma correcta y compatible de agregar comandos de la CLI a Magento 2

9

¿Existe una forma correcta y oficialmente admitida de agregar sus comandos CLI a un módulo Magento 2? Por lo que he reunido, sus opciones son

  1. Agregue su clase de comando al commandsargumento de a Magento\Framework\Console\CommandListtravés de un di.xmlarchivo

  2. Registre su comando a través \Magento\Framework\Console\CommandLocator::registerde un registration.phparchivo o un cli_commands.phparchivo

Ninguna de estas opciones está bendecida con un @api. No está claro, como desarrolladores de extensiones, cómo debemos agregar los scripts de línea de comandos para que se queden en cada versión.

¿Alguien sabe si hay una política oficial de Magento sobre The Right ™ para hacer esto?

Alan Storm
fuente

Respuestas:

6

cli_commands.phpdebe usarse en caso de que el comando se agregue en un paquete no modular. Entonces, si el comando está en el módulo y está bien (esperado) que esté disponible solo cuando el módulo está habilitado, di.xmldebe usarse. Si no desea agregar un módulo y desea tener solo un paquete de Compositor arbitrario, puede usarlo cli_commands.phppara registrar el comando allí. Por supuesto, debería ser realmente independiente de Magento. O, por ahora, este enfoque se puede usar para registrar los comandos necesarios incluso si un módulo está deshabilitado (asegúrese de que no se base en la lógica de ningún Módulo que funcione solo cuando está habilitado).

BuskaMuza
fuente
11

La forma correcta es:

Cree su módulo como lo hace para cualquier tipo de módulo

Solo crea tu registration.phparchivo

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'My_Module',
    __DIR__
);

Y crea tu module.xmlarchivo:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="My_Module" setup_version="0.1.0">
    </module>
</config>

Agregar una entrada en di.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="my_command" xsi:type="object">My\Module\Command\Mycommand</item>
            </argument>
        </arguments>
    </type>
</config>

Crea tu clase de comando:

<?php
namespace My\Module\Command;

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

class Mycommand extends Command
{
    protected function configure()
    {
        $this->setName('my:command');
        $this->setDescription('Run some task');

        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('Hello world!');
    }
}

Para ejecutar su tarea simplemente escriba:

php bin/magento my:command

Sobre compatibilidad:

@api no es necesario para los comandos, se usa para contratos de servicio AFAIK.

Si necesita dejarlos compatibles, simplemente use una API de interfaz dentro de su script en lugar de poner la lógica dentro de él.

Por ejemplo:

<?php
use My\Module\Api\TaskInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class MyCommand extends Command
{
    protected $taskInterface;

    public function __construct(
        TaskInterface $taskInterface
    ) {
        $this->taskInterface= $taskInterface;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('my:command');
        $this->setDescription('Run some task');

        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->taskInterface->runTask();

        $output->writeln('Done.');
    }
}
Phoenix128_RiccardoT
fuente
1
Información útil, +1, pero ¿estás seguro de eso? Los módulos de datos de muestra de Magento usan el método cli_commands.php, y eso parece más limpio, y es menos probable que se rompa si Magento cambia la implementación deMagento\Framework\Console\CommandList
Alan Storm
No estoy 100% seguro, solo Magento itslef puede responder esto, pero he estado jugando un rato y si eliminas "cli_commands.php" aún verás tu comando disponible en tu bin / magento. También los declararon en di.xml, por lo que creo que todavía es algo de la versión beta. Como si fuera para constructores y fábricas. Si ve, cli_command.php solo se usa en datos de muestra.
Phoenix128_RiccardoT
¿Qué te hace decir que @api quedará en desuso?
Kristof en Fooman
@ Kristof, lamento no haber entendido correctamente una de las diapositivas de la solución de socios capacitados, así que ignore esa oración. Modifiqué mi publicación eliminándola.
Phoenix128_RiccardoT
3

si lo entendí bien, los comandos definidos en la Lista de comandos sobre DI solo están disponibles en una Instancia Magento instalada y también solo para los Módulos Magento (ya que deben definirse en el di.xml): https://github.com/magento /magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/lib/internal/Magento/Framework/Console/Cli.php#L124

Magento \ Framework \ App \ DeploymentConfig :: isAvailable () en el método anterior busca una fecha de instalación en la configuración para verificar si hay un Magento2 instalado: https://github.com/magento/magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/lib/ interno / Magento / Framework / App / DeploymentConfig.php # L83 ).

Los comandos definidos en Magento \ Framework \ Console \ CommandLocator, por otro lado, siempre están disponibles e incluso pueden ser definidos por módulos que no son de Magento a través del método estático CommandLocator :: register en un archivo cargado automáticamente por el compositor (por ejemplo cli_commands.php)

https://github.com/magento/magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/lib/internal/Magento/Framework/Console/Cli.php#L130

https://github.com/magento/magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/lib/internal/Magento/Framework/Console/Cli.php#L146

Entonces, creo que ambos métodos son necesarios y tienen derecho a existir

David Verholen
fuente
Esa es una buena observación +1, pero ¿por qué debería necesitar un script Magento mientras el módulo relacionado no está instalado?
Phoenix128_RiccardoT
1
se trata de que la instancia de magento no esté instalada. Hay varios comandos disponibles antes de instalar magento2. Por ejemplo, el comando sampledata: deploy, que tiene sentido si desea instalar directamente los datos de muestra con la configuración de magento2.
David Verholen
Creo que tienes razón. Entonces, la forma "correcta" para un módulo Magento es usar di.xml (como en mi respuesta) y usar "cli_command.php" cuando necesita ejecutar alguna tarea antes de instalar su módulo. Tiene sentido
Phoenix128_RiccardoT
vosotros, creo que debería ser eso. +1 porque creo que tienes la respuesta correcta (y muy bien explicada), pero esto no encaja en un comentario;)
David Verholen
Gracias @David Verholen, mi +1 significa que te di +1, no es que merecieras solo un +1;)
Phoenix128_RiccardoT