Edit in GitHubLog an issue

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.


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 the configure() method of the Command class:

    Copied to your clipboard
    1protected function configure(): void
    3 $this->setName('my:first:command');
    4 $this->setDescription('This is my first console command.');
    6 parent::configure();

    or in the di.xml file:

    Copied to your clipboard
    1<?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 ...

    or in the __construct method (declaration is similar to di.xml):

    Copied to your clipboard
    1public function __construct()
    3 parent::__construct('my:first:command');

    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:

  1. 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 clipboard
    5namespace Magento\CommandExample\Console\Command;
    7use 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;
    13class SomeCommand extends Command
    15 private const NAME = 'name';
    17 protected function configure(): void
    18 {
    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 );
    28 parent::configure();
    29 }
    31 /**
    32 * Execute the command
    33 *
    34 * @param InputInterface $input
    35 * @param OutputInterface $output
    36 *
    37 * @return int
    38 */
    39 protected function execute(InputInterface $input, OutputInterface $output): int
    40 {
    41 $exitCode = 0;
    43 if ($name = $input->getOption(self::NAME)) {
    44 $output->writeln('<info>Provided name is `' . $name . '`</info>');
    45 }
    47 $output->writeln('<info>Success message.</info>');
    48 $output->writeln('<comment>Some comment.</comment>');
    50 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 }
    62 return $exitCode;
    63 }

    Style the output text by using <error>, <info>, or <comment> tags. See Symfony documentation for more information about styling.

  2. 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 clipboard
    1<?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 ...
  3. Clean the cache:

    Copied to your clipboard
    bin/magento cache:clean
  4. Regenerate the code:

    Copied to your clipboard
    bin/magento setup:di:compile


As a result, the new command my:first:command that accepts a --name parameter is ready to use.

Copied to your clipboard
bin/magento my:first:command --name 'John'
Was this helpful?
  • Privacy
  • Terms of Use
  • Do not sell my personal information
  • AdChoices
Copyright © 2022 Adobe. All rights reserved.