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"?-->
InchooReindexRequiredConsoleCommandIndexerReindexRequiredCommand
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 MagentoIndexerConsoleCommandAbstractIndexerManageCommand
, 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 InchooReindexRequiredConsoleCommand;
class IndexerReindexRequiredCommand extends MagentoIndexerConsoleCommandAbstractIndexerManageCommand
{
}
If we look at the parent class, there are no __construct()
method declared, so we need to look at the parent of that class. MagentoIndexerConsoleCommandAbstractIndexerCommand
Class MagentoIndexerConsoleCommandAbstractIndexerCommand
requires one class to be injected:
MagentoFrameworkAppObjectManagerFactory
In our class we do the following:
public function __construct(
MagentoFrameworkAppObjectManagerFactory $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 SymfonyComponentConsoleCommandCommand
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.