Command to reindex required indexers

Related Inchoo Services

You are in a hurry and you do not want to manually type indexer codes to reindex? Well sit back and keep reading, you are in for a treat.

By default, Magento has these console commands for the indexer

indexer

  • indexer:info – Shows allowed Indexers
  • indexer:reindex – Reindexes Data
  • indexer:reset – Resets indexer status to invalid
  • indexer:set-mode – Sets index mode type
  • indexer:show-mode – Shows Index Mode
  • indexer:status – Shows status of Indexer

So you probably asking yourself why do I need a custom command to reindex required (invalidated) indexers?
Well, we are kinda lazy and this command can save you some precious time you can spend on other things. Instead of writing this command:

bin/magento indexer:reindex customer_grid catalog_product_flat ...and other invalidated indexers...

we will be using this:

bin/magento indexer:reindex:required

Module

To get started we need to create a new module, there are plenty of tutorials online how to create a new module, so we will skip that and dig into juicy stuff.

To add a new command you need to create di.xml and put this in:

<?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="required" xsi:type="object">Inchoo\ReindexRequired\Console\Command\IndexerReindexRequiredCommand</item>
            </argument>
        </arguments>
    </type>
</config>

We are giving our command unique name = "required" (note that this is just internal indentifier) and class we will be using to execute the command.

Class

Next, we will create a IndexerReindexRequiredCommand class which will extend \Magento\Indexer\Console\Command\AbstractIndexerManageCommand, because we are adding a command related to the indexers and there is no point to do it from scratch when Magento already have what we need.

namespace Inchoo\ReindexRequired\Console\Command;
 
class IndexerReindexRequiredCommand extends \Magento\Indexer\Console\Command\AbstractIndexerManageCommand
{
}

If we look at the parent class, there are no __construct() method declared, so we need to look at the parent of that class. \Magento\Indexer\Console\Command\AbstractIndexerCommand

Class \Magento\Indexer\Console\Command\AbstractIndexerCommand requires one class to be injected:
\Magento\Framework\App\ObjectManagerFactory

In our class we do the following:

public function __construct(
    \Magento\Framework\App\ObjectManagerFactory $objectManagerFactory
) {
    parent::__construct($objectManagerFactory);
}

Configure

Next, we create configure() method to give our command a name and description.

protected function configure()
{
    $this->setName('indexer:reindex:required')
        ->setDescription('Reindexes Required/Invalidated Data')
        ->setDefinition($this->getInputList());
 
    parent::configure();
}

Our new command will now show up in terminal when we execute the bin/magento.

Execute

The next step is to create the execute function and bring our command to life.

public function execute(InputInterface $input, OutputInterface $output)
{
 
}

Well now, what do we need to do? We need to somehow write in terminal. We put two arguments into our function InputInterface $input and OutputInterface $output. $input is used to get arguments from terminal and $output is used to, you guess output something to terminal. We will not use $input anywhere in our code but we need to implement it because \Symfony\Component\Console\Command\Command demands it.

If we look into the class IndexerReindexCommand, Magento defines $returnValue with a constant of Cli::RETURN_FAILURE. This will be used on the end by exit function. For more information about that function go check: http://php.net/manual/en/function.exit.php.

To get all indexers we have in our Magento installation we simply call the $this->getAllIndexers(), located in AbstractIndexerCommand class and for each indexer we will check if it is valid or not and reindex it. Simple enough?

Validate

Well, we are not quite there yet. What if our indexer is in the middle of a process started by e.g. cron? We need to validate indexer status before doing anything else with him.

public function execute(InputInterface $input, OutputInterface $output)
{
    $returnValue = Cli::RETURN_FAILURE;
    foreach ($this->getAllIndexers() as $indexer) {
        try {
            $this->validateIndexerStatus($indexer);
 
        } catch (LocalizedException $e) {
            $output->writeln($e->getMessage());
        } catch (\Exception $e) {
            $output->writeln($indexer->getTitle() . ' indexer process unknown error:');
            $output->writeln($e->getMessage());
        }
    }
    return $returnValue;
}

Our validateIndexerStatus function will look like this.

/**
 * Validate that indexer is not locked or not needed to be reindexed
 *
 * @param IndexerInterface $indexer
 * @return void
 * @throws LocalizedException
 */
private function validateIndexerStatus(IndexerInterface $indexer)
{
    if ($indexer->getStatus() == StateInterface::STATUS_WORKING) {
        throw new LocalizedException(
            __(
                '%1 index is locked by another reindex process. Skipping.',
                $indexer->getTitle()
            )
        );
    } elseif ($indexer->getStatus() == StateInterface::STATUS_VALID) {
        throw new LocalizedException(
            __(
                '%1 index is valid. Skipping.',
                $indexer->getTitle()
            )
        );
    }
}

If the indexer have working or valid status, throw appropriate exceptions which we catch in try block.
Now we can write code that will reindex the indexer $indexer->reindexAll() and to get how much time is spent reindexing, we need to add $startTime = microtime(true); before the reindex code and this code $resultTime = microtime(true) - $startTime; after the reindex.

End

For the end, we will output some success message with the time spent.

$output->writeln(
                    $indexer->getTitle() . ' index has been rebuilt successfully in ' . gmdate('H:i:s', $resultTime)
                );

This is full execute function:

public function execute(InputInterface $input, OutputInterface $output)
{
    $returnValue = Cli::RETURN_FAILURE;
    foreach ($this->getAllIndexers() as $indexer) {
        try {
            $this->validateIndexerStatus($indexer);
 
            $startTime = microtime(true);
            $indexer->reindexAll();
            $resultTime = microtime(true) - $startTime;
            $output->writeln(
                $indexer->getTitle() . ' index has been rebuilt successfully in ' . gmdate('H:i:s', $resultTime)
            );
 
            $returnValue = Cli::RETURN_SUCCESS;
        } catch (LocalizedException $e) {
            $output->writeln($e->getMessage());
        } catch (\Exception $e) {
            $output->writeln($indexer->getTitle() . ' indexer process unknown error:');
            $output->writeln($e->getMessage());
        }
    }
    return $returnValue;
}

Let’s test it if this works. In root Magento dir type bin/magento indexer:reindex:required or just bin/magento in:re:re. You will see a outputed lines of skipped/reindexed indexers.

You can check the source code on GitHub https://github.com/ivan-veres/magento2-module-reindex-required/.

Hope this little tutorial and this module will help someone.

You made it all the way down here so you must have enjoyed this post! You may also like:

Google Image indexing and Magento [robots.txt] Drazen Karacic-Soljic
, | 3

Google Image indexing and Magento [robots.txt]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.