8

I am having a problem that I have costumer groups in our shop. When new customer is created and customer discount group is changed form BE. The customer cannot see their new prices. New customer sees there prices only after re-indexing. So I am looking for a way how to run reindexer after customer group change in BE using observer.

6 Answers 6

11

Mainly you need to fire product related indexing.

So you need to initialize IndexerFactory following way.


/**
     * @var \Magento\Indexer\Model\IndexerFactory
     */
    protected $indexerFactory;

    public function __construct(
        \Magento\Indexer\Model\IndexerFactory $indexerFactory
    ) {
        $this->indexerFactory = $indexerFactory;
    }

and your function need to add following code:


foreach ($indexerIds as $indexerId) {
                    $indexer = $this->indexerFactory->create();
                    $indexer->load($indexerId);
                    $indexer->reindexAll();
                }

here $indexerIds is an array of $indexerId (e.g: catalog_category_product ,catalog_product_category etc)

Here is an module that's help you a lot Click Here

2
  • You could explain how to get the indexer ids.
    – CarComp
    Oct 5, 2016 at 15:03
  • $indexerIds are cataloginventory_stock, catalogrule_rule, catalogrule_product etc
    – Sohel Rana
    Oct 5, 2016 at 18:32
9
 <?php
 namespace Vendor\ModuleName\Controller;
 class Reindex extends \Magento\Framework\App\Action\Action
 {  
CONST PRICE_INDEXER_ID = 'catalog_product_price';
/**
 * @var \Magento\Indexer\Model\IndexerFactory
 */
protected $indexerFactory;
/**
 * @var \Magento\Framework\Indexer\ConfigInterface
 */
protected $config;
/**
 * @param Context $context
 * @param \Magento\Indexer\Model\IndexerFactory $resultLayoutFactory    
 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
 */
public function __construct(
    \Magento\Framework\App\Action\Context $context,
    \Magento\Indexer\Model\IndexerFactory $indexerFactory,
    \Magento\Framework\Indexer\ConfigInterface $config
) {     
    $this->indexerFactory = $indexerFactory;
    $this->config = $config;
    parent::__construct($context);
}
/**
 * Regenerate full index
 *
 * @return void
 * @throws \Exception
 */
public function execute()
{
    $params = $this->getRequest()->getParams();
    if(isset($params['run'])){
        if($params['run'] == 'all'){
            $this->reindexAll(); 
        }else{
            $this->reindexOne($params['run']);
        }   
    }   
}
/**
 * Regenerate single index
 *
 * @return void
 * @throws \Exception
 */
private function reindexOne($indexId){
    $indexer = $this->indexerFactory->create()->load($indexId);
    $indexer->reindexAll();
}
/**
 * Regenerate all index
 *
 * @return void
 * @throws \Exception
 */
private function reindexAll(){
    foreach (array_keys($this->config->getIndexers()) as $indexerId) {          
        $indexer = $this->indexerFactory->create()->load($indexerId);
        $indexer->reindexAll();            
    }
}

API : https://www.website.com/routername/controllername(reindex)/run/indexer_id(catalog_product_price)

EX: https://www.webizon.in/apimodule/reindex/run/catalog_product_price

To re-index all run : https://www.webizon.in/apimodule/reindex/run/all

List of reindex id's:

  1. design_config_grid
  2. customer_grid
  3. catalog_product_flat
  4. catalog_category_flat
  5. catalog_category_product
  6. catalog_product_category
  7. catalogrule_rule
  8. catalog_product_attribute
  9. cataloginventory_stock
  10. catalog_product_price
  11. catalogrule_product
  12. catalogsearch_fulltext

I did this for my company wants like API method. I think this will help to someone. thanks. thumps up. Source: http://www.webizon.in/magento-2-re-indexing-programmatically/

1
  • Appreciate your post is it use full and work done in some hours if i have 60 million product and run the indexing from this method.Because from indexer:reindex command it will take around 100 hr but still it is not completed or have you any idea about completion of that process.
    – Prits
    Dec 31, 2020 at 11:22
3

Extending upon this answer, here is some more details on how to reindex, how to get the IDs, and reindexing only what is needed. ReindexAll can add a lot of overhead, especially on very large catalogs / sites.

public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Indexer\Model\IndexerFactory $indexerFactory,
        \Magento\Indexer\Model\Indexer\CollectionFactory $indexerCollectionFactory
    ) {
        $this->eavConfigFactory = $eavConfigFactory;
        $this->eavSetupFactory = $eavSetupFactory;
        $this->customerSetupFactory = $customerSetupFactory;
        $this->indexerFactory = $indexerFactory;
        $this->indexerCollectionFactory = $indexerCollectionFactory;
        parent::__construct($context);
    }

Then, when you want to use it:

public function ensureIndexersAreReady() {
    // Make sure the indexes are ready
    $indexer = $this->indexerFactory->create();
    $indexerCollection = $this->indexerCollectionFactory->create();

    $ids = $indexerCollection->getAllIds();
    foreach ($ids as $id){
        $idx = $indexer->load($id);
        if ($idx->getStatus() != 'valid'){
             $idx->reindexRow($id);
        }
    }
}
0

And for those who stumbled upon this page while searching for a way to reindex all, here is a gist that does the trick: https://gist.github.com/herveguetin/f021e2c4e06b755e5a880175b499f0bd

0

I based my code on the previous answers:

<?php

namespace {Vendor}\{Module}\{the_path_you_decide};

class IndexerManager {

    private \Psr\Log\LoggerInterface $logger;
    private \Magento\Indexer\Model\IndexerFactory $indexerFactory;
    private \Magento\Indexer\Model\Indexer\CollectionFactory $indexerCollectionFactory;

    public function __construct(
        \Psr\Log\LoggerInterface $logger,
        \Magento\Indexer\Model\IndexerFactory $indexerFactory,
        \Magento\Indexer\Model\Indexer\CollectionFactory $indexerCollectionFactory
    ) {
        $this->logger = $logger;
        $this->indexerFactory = $indexerFactory;
        $this->indexerCollectionFactory = $indexerCollectionFactory;
    }
 
    /**
     * @return array
     */
    public function getIndexerIds(){
        /** @var \Magento\Indexer\Model\Indexer\Collection */
        $indexerCollection = $this->indexerCollectionFactory->create();
        $indexerIds = $indexerCollection->getAllIds();
        return $indexerIds;
    }

    /**
     * @param array $indexerIds
     * @return void
     */
    public function reindex($indexerIds) {
        try {
            foreach ($indexerIds as $indexerId) {
                $indexer = $this->indexerFactory->create();
                $indexer->load($indexerId);
                $indexer->reindexAll();
            }
            echo 'Rebuilding indexers: ' . print_r($indexerIds,true) . "\xA";
            $this->logger->info('Rebuilding indexers: ' . print_r($indexerIds,true));
        } catch (\Throwable $ex) {
            echo 'Error Message: ' . $ex->getMessage() . "\xA";
            $this->logger->error('Error Message: ' . $ex->getMessage());
        }
    }

}

?>

And you can test the code with a test.php file

<?php

use Magento\Framework\App\Bootstrap;
include_once(__DIR__ . '/path to the bootstrap file');

use {Vendor}\{Module}\{the_path_you_decide}\IndexerManager;
include_once(__DIR__ . '/IndexerManager.php');

function testReindexAll(){
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    //If you haven't run the "bin/magento setup:di:compile" command, instantiate the IndexerManager class like this:
    $indexerManager = new IndexerManager(
        $objectManager->get(\Psr\Log\LoggerInterface::class),
        $objectManager->get(\Magento\Indexer\Model\IndexerFactory::class),
        $objectManager->get(\Magento\Indexer\Model\Indexer\CollectionFactory::class)
    );
    //If the class is already compiled, you can instantiate the IndexerManager like this:
    $indexerManager = $objectManager->get(IndexerManager::class);
    $indexerIds = $indexerManager->getIndexerIds();//get all indexer ids
    $indexerManager->reindex($indexerIds);//rebuild all magento indexers
}

function runIndexerManagerTest(){
    Bootstrap::create(BP, $_SERVER);
    testReindexAll();
}

runIndexerManagerTest();

In console, run: php test.php

0

It is first result in Google after put "run indexer programmatically" so I thnik there should be better solution used.

/**
* @var \Magento\Indexer\Model\Indexer\CollectionFactory
*/
protected $indexerCollectionFactory;    

protected function reindex() 
{
   $indexerCollection = $this->indexerCollectionFactory->create();
   /** @var  Indexer $item */
   foreach ($indexerCollection->getItems() as $item) {
   if (in_array($item->getId(),'catalog_product_attribute','cataloginventory_stock'])) {
       $item->invalidate();
   }
}

If you wanna mark all indexer as invalid then just remove the if. This solution will work only when you use Cron to rebuild the indexers. It is recommended solution. If you have indexer updated at save action then you need to use:

$item->reindexRow($item->getId())

In upper example instead invalidate method.

Of course you need to inject $indexerCollectionFactory in your __construct method

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.