In Magento 2, the platform introduced a new command line interface called bin/magento
that is included in every installation. Most Magento developers are familiar with it because it makes it very easy to peform common tasks on the install like clear cache and install a database. What you might not know is that you can add custom commands to the Magento CLI to allow you to run your own code. I have used this feature to create custom cron jobs that can be executed by the OS cron instead of Magento's cron system. Magento's CLI is based on the Symfony Console package which is commonly used in the PHP ecosystem. Laravel bases their artisan
command on Symfony Console, for example. In Magento 2, you can create custom Symfony Console commands and include them in Magento's CLI. To help other developers get started with console commands, I want to provide this quick tutorial.
I am assuming you have a Magento 2 installation ready to use for development. To learn how to set up Magento, check out Magento's devdocs post for installation instructions. I used Magento Community 2.3.1 for this tutorial.
1. Make a Module
We need to create our own custom module in app/code
. I am calling my module Restoreddev_Console
. For every module we need a registration.php
and module.xml
file.
app/code/Restoreddev/Console/registration.php
<?php
use \Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Restoreddev_Console', __DIR__);
app/code/Restoreddev/Console/etc/module.xml
<?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="Restoreddev_Console" />
</config>
Now you can run php bin/magento setup:upgrade
to install your custom module into Magento's database.
2. Create Console Command Class
Next, we can create a class that implements Symfony Command that will be run when our command is executed. I want to create a custom command that clears the generated
directory, similar to how cache:flush
works. Add this class to your module:
app/code/Restoreddev/Console/Console/Command/GeneratedFlushCommand.php
<?php
namespace Restoreddev\Console\Console\Command;
use Symfony\Component\Console\Command\Command;
use Magento\Framework\Filesystem\DirectoryList;
use Magento\Framework\Filesystem\Io\File as FileIo;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class GeneratedFlushCommand extends Command
{
protected $fileIo;
protected $directoryList;
public function __construct(
FileIo $fileIo,
DirectoryList $directoryList
) {
parent::__construct();
$this->fileIo = $fileIo;
$this->directoryList = $directoryList;
}
protected function configure()
{
$this->setName('generated:flush');
$this->setDescription('Deletes code in generated folder');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$path = $this->directoryList->getPath('generated');
$dirs = glob("$path/*", GLOB_ONLYDIR);
foreach ($dirs as $dir) {
$this->fileIo->rmdir($dir, $recursive = true);
}
$output->writeln('Generated folder successfully flushed');
}
}
There is a lot happening in this class, so we need to analyze it in sections.
- You will see that the class extends
Symfony\Component\Console\Command\Command
. The Symfony parent class provides the interface for our class to be included in the command list. - In the
__construct
method, we can inject Magento dependencies like other Magento classes. However, you do have to runparent::__construct();
for the class to be implemented properly. - The
configure
method allows you to define the command name and description that appears in the CLI menu. - The
execute
method contains the code that will run when the CLI command is executed. The method receives two objects:$input
(contains any console arguments) and$output
(allows you to send text to the terminal). I am using Magento's classes to get thegenerated
directory and to delete any directories inside of it. At the end, I am using$output->writeln()
to send a success message to the user.
3. Register Command in Magento
Finally, we need to register the command in Magento's dependency injection system. Create the following di.xml
file in your module.
app/code/Restoreddev/Console/etc/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\CommandListInterface">
<arguments>
<argument name="commands" xsi:type="array">
<item name="generatedFlushCommand" xsi:type="object">Restoreddev\Console\Console\Command\GeneratedFlushCommand</item>
</argument>
</arguments>
</type>
</config>
In the di.xml
, we are targeting the CommandListInterface
and adding an additional command to its arguments. Now you can flush Magento's cache (php bin/magento cache:flush
) and run php bin/magento
. You will see a new command called generated:flush
. If you execute it php bin/magento generated:flush
, then you will see all subdirectories in the generated
folder have been deleted.
I hope this quick tutorial has helped you learn about a neat new feature in Magento 2. If you would like to see another specific Magento tutorial, let me know in the comments!
Top comments (4)
Good stuff.
Can you make a tutorial how to create a custom EAV in Magento 2?
I am not talking about adding custom attributes to already existent EAV models but rather to create a new one.
So a completely new entity, but it uses EAV tables for storage? I haven't done that before, but it would make for an interesting post. Thanks for the suggestion!
I tired learning that myself, but I could not figure it out.
Seems like a very complex system too me.
If you could figure it out for us then we'd be very grateful :P
Sounds like a good challenge! What type of data were you trying to store using EAV?