Create a custom command
Adobe Commerce and Magento Open Source enables your component to add commands to our Symfony-like command-line interface (CLI).
Commerce has one command-line interface that performs both installation and configuration tasks: <magento_root>/bin/magento
. The new interface performs multiple tasks, including:
- Installing Commerce (and related tasks such as creating or updating the database schema, creating the deployment configuration, and so on).
- Clearing the cache.
- Managing indexes, including reindexing.
- Creating translation dictionaries and translation packages.
- Generating non-existent classes such as factories and interceptors for plug-ins, generating the dependency injection configuration for the object manager.
- Deploying static view files.
- Creating CSS from Less.
Other benefits:
- A single command (
<magento_root>/bin/magento list
) lists all available installation and configuration commands. - Consistent user interface based on Symfony.
- The CLI is extensible so third party developers can "plug in" to it. This has the additional benefit of eliminating users' learning curve.
- Commands for disabled modules do not display.
Prerequisites#
Before you begin, make sure you understand the following:
All Magento command-line interface (CLI) commands rely on the application and must have access to its context, dependency injections, plug-ins, and so on.
All CLI commands should be implemented in the scope of your module and should depend on the module's status.
Your command can use the Object Manager and dependency injection features; for example, it can use constructor dependency injection.
Your command should have an unique
name
, defined in theconfigure()
method of the Command class:Copied to your clipboard1protected function configure(): void2{3 $this->setName('my:first:command');4 $this->setDescription('This is my first console command.');56 parent::configure();7}8...or in the
di.xml
file:Copied to your clipboard1<?xml version="1.0"?>2<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">3 ...4 <type name="Magento\CommandExample\Console\Command\SomeCommand">5 <arguments>6 <!-- configure the command name via constructor $name argument -->7 <argument name="name" xsi:type="string">my:first:command</argument>8 </arguments>9 </type>10 ...11</config>or in the
__construct
method (declaration is similar todi.xml
):Copied to your clipboard1public function __construct()2{3 parent::__construct('my:first:command');4}Otherwise the Symfony framework will return an
The command defined in "<Command class>" cannot have an empty name.
error.
Add CLI commands using dependency injection#
The sample modules provide a demonstration of many programming techniques, including adding a CLI command using dependency injection. Look at the sample-module-command
for an example. The module's README.md discusses how to install it.
Following is a summary of the process:
Create a Command class (the recommended location is
<your component root dir>/Console/Command
).See
<Magento_Store_module_dir>/Console/Command/StoreListCommand.php
for example.Copied to your clipboard1<?php23declare(strict_types=1);45namespace Magento\CommandExample\Console\Command;67use Magento\Framework\Exception\LocalizedException;8use Symfony\Component\Console\Command\Command;9use Symfony\Component\Console\Input\InputInterface;10use Symfony\Component\Console\Input\InputOption;11use Symfony\Component\Console\Output\OutputInterface;1213class SomeCommand extends Command14{15 private const NAME = 'name';1617 protected function configure(): void18 {19 $this->setName('my:first:command');20 $this->setDescription('This is my first console command.');21 $this->addOption(22 self::NAME,23 null,24 InputOption::VALUE_REQUIRED,25 'Name'26 );2728 parent::configure();29 }3031 /**32 * Execute the command33 *34 * @param InputInterface $input35 * @param OutputInterface $output36 *37 * @return int38 */39 protected function execute(InputInterface $input, OutputInterface $output): int40 {41 $exitCode = 0;4243 if ($name = $input->getOption(self::NAME)) {44 $output->writeln('<info>Provided name is `' . $name . '`</info>');45 }4647 $output->writeln('<info>Success message.</info>');48 $output->writeln('<comment>Some comment.</comment>');4950 try {51 if (rand(0, 1)) {52 throw new LocalizedException(__('An error occurred.'));53 }54 } catch (LocalizedException $e) {55 $output->writeln(sprintf(56 '<error>%s</error>',57 $e->getMessage()58 );59 $exitCode = 1;60 }6162 return $exitCode;63 }64}Style the output text by using
<error>
,<info>
, or<comment>
tags. See Symfony documentation for more information about styling.Declare your Command class in
Magento\Framework\Console\CommandListInterface
and configure the command name using dependency injection (<your component root dir>/etc/di.xml
):Copied to your clipboard1<?xml version="1.0"?>2<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">3 ...4 <type name="Magento\Framework\Console\CommandListInterface">5 <arguments>6 <argument name="commands" xsi:type="array">7 <item name="commandexample_somecommand" xsi:type="object">Magento\CommandExample\Console\Command\SomeCommand</item>8 </argument>9 </arguments>10 </type>11 ...12</config>Clean the cache:
Copied to your clipboardbin/magento cache:cleanRegenerate the code:
Copied to your clipboardbin/magento setup:di:compile
Result#
As a result, the new command my:first:command
that accepts a --name
parameter is ready to use.
Copied to your clipboardbin/magento my:first:command --name 'John'