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
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
-
-
$indexerIds are cataloginventory_stock, catalogrule_rule, catalogrule_product etc Oct 5, 2016 at 18:32
<?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:
- design_config_grid
- customer_grid
- catalog_product_flat
- catalog_category_flat
- catalog_category_product
- catalog_product_category
- catalogrule_rule
- catalog_product_attribute
- cataloginventory_stock
- catalog_product_price
- catalogrule_product
- 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/
-
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.– PritsDec 31, 2020 at 11:22
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);
}
}
}
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
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
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