Manière correcte et prise en charge d'ajouter des commandes CLI à Magento 2

9

Existe-t-il un moyen correct et officiellement pris en charge d'ajouter vos commandes CLI à un module Magento 2? D'après ce que j'ai rassemblé, vos options sont

  1. Ajoutez votre classe de commande à l' commandsargument de Magento\Framework\Console\CommandListvia un di.xmlfichier

  2. Enregistrez votre commande via \Magento\Framework\Console\CommandLocator::registerdans un registration.phpfichier ou un cli_commands.phpfichier

Aucune de ces options n'est dotée d'un @api. En tant que développeurs d'extensions, il n'est pas clair comment ajouter des scripts de ligne de commande de manière à ce qu'ils restent d'une version à l'autre.

Est-ce que quelqu'un sait s'il existe une politique officielle de Magento sur la bonne façon de procéder?

Alan Storm
la source

Réponses:

6

cli_commands.phpdoit être utilisé dans le cas où la commande est ajoutée dans un package non modulaire. Donc, si la commande est dans le module et qu'il est OK (attendu) qu'elle ne soit disponible que lorsque le module est activé, elle di.xmldoit être utilisée. Si vous ne voulez pas ajouter de module et que vous voulez juste un package Composer arbitraire, vous pouvez utiliser cli_commands.phppour y enregistrer la commande. Bien sûr, il devrait alors être vraiment indépendant de Magento. Ou, pour l'instant, cette approche peut être utilisée pour enregistrer les commandes nécessaires même si un module est désactivé (assurez-vous qu'il ne repose sur aucune logique de module qui ne fonctionne que lorsqu'il est activé).

BuskaMuza
la source
11

La bonne façon est:

Créez votre module comme vous le faites pour tout type de module

Créez simplement votre registration.phpfichier

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

Et créez votre module.xmlfichier:

<?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>

Ajoutez une entrée dans 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>

Créez votre classe de commande:

<?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!');
    }
}

Pour exécuter votre tâche, tapez simplement:

php bin/magento my:command

À propos de la compatibilité:

@api n'est pas nécessaire pour les commandes, il est utilisé pour les contrats de service AFAIK.

Si vous devez les laisser compatibles, utilisez simplement une API d'interface dans votre script au lieu de mettre la logique à l'intérieur.

Par exemple:

<?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
la source
1
Informations utiles, +1, mais en êtes-vous sûr? Les exemples de modules de données Magento utilisent la méthode cli_commands.php, et cela semble plus propre, et moins susceptible de se casser si Magento change l'implémentation deMagento\Framework\Console\CommandList
Alan Storm
Je ne suis pas sûr à 100%, seul Magento lui-même peut y répondre, mais j'y ai joué un certain temps et si vous supprimez "cli_commands.php", vous verrez toujours votre commande disponible dans votre bin / magento. Ils les ont également déclarés sur di.xml, donc je pense que c'est toujours quelque chose de la version bêta. Comme pour les constructeurs et les usines. Si vous voyez, cli_command.php n'est utilisé que dans les échantillons de données.
Phoenix128_RiccardoT
Qu'est-ce qui vous fait dire que @api va devenir obsolète?
Kristof au Fooman
@Kristof, désolé de ne pas avoir correctement compris l'une des diapositives de la solution de partenaire formé, alors ignorez cette phrase. J'ai modifié mon message en le supprimant.
Phoenix128_RiccardoT
3

si je comprends bien, les commandes définies dans la CommandList sur DI ne sont disponibles que dans une instance Magento installée et uniquement pour les modules Magento (car elles doivent être définies dans le di.xml): https://github.com/magento /magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/lib/internal/Magento/Framework/Console/Cli.php#L124

Magento \ Framework \ App \ DeploymentConfig :: isAvailable () dans la méthode ci-dessus vérifie une date d'installation dans la configuration pour rechercher un Magento2 installé: https://github.com/magento/magento2/blob/6352f8fbca2cbf21de88db0cf7f4555bfc60451c/l internal / Magento / Framework / App / DeploymentConfig.php # L83 ).

Les commandes définies dans Magento \ Framework \ Console \ CommandLocator par contre sont toujours disponibles et peuvent même être définies par des modules non Magento via la méthode statique CommandLocator :: register dans un fichier chargé automatiquement par le compositeur (par exemple 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

Je pense donc que les deux méthodes sont nécessaires et ont leur droit d'exister

David Verholen
la source
C'est une bonne observation +1, mais pourquoi devriez-vous avoir besoin d'un script Magento alors que le module associé n'est pas installé?
Phoenix128_RiccardoT
1
il s'agit de l'instance de magento qui n'est pas installée. Plusieurs commandes sont disponibles avant d'installer magento2. Par exemple, la commande sampledata: deploy, qui a du sens si vous souhaitez installer directement les exemples de données avec la configuration magento2.
David Verholen
Je pense que tu as raison. Donc, la façon "correcte" pour un module Magento est d'utiliser di.xml (comme dans ma réponse) et d'utiliser "cli_command.php" lorsque vous devez exécuter une tâche avant l'installation de votre module. Cela a du sens.
Phoenix128_RiccardoT
vous, je pense que ça devrait être ça. +1 parce que je pense que vous avez la bonne réponse (et très bien expliquée), mais cela ne correspondait pas à un commentaire;)
David Verholen
Merci @David Verholen, mon +1 signifiait que je vous ai donné +1, pas que vous méritiez juste un +1;)
Phoenix128_RiccardoT