Skip to content

Commit

Permalink
Merge pull request #8 from aligent/feature/BEG-81_category_indexing
Browse files Browse the repository at this point in the history
BEG-81: Add re-caching of category URLs
  • Loading branch information
aligent-lturner authored Jun 28, 2022
2 parents 1fc0dfd + e8306de commit 959f78f
Show file tree
Hide file tree
Showing 10 changed files with 521 additions and 7 deletions.
153 changes: 153 additions & 0 deletions Model/Indexer/Category/CategoryIndexer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?php
/*
* Copyright (c) Aligent Consulting. All rights reserved.
*/

declare(strict_types=1);

namespace Aligent\PrerenderIo\Model\Indexer\Category;

use Aligent\PrerenderIo\Api\PrerenderClientInterface;
use Aligent\PrerenderIo\Helper\Config;
use Aligent\PrerenderIo\Model\Url\GetUrlsForCategories;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\RuntimeException;
use Magento\Framework\Indexer\ActionInterface as IndexerActionInterface;
use Magento\Framework\Indexer\DimensionalIndexerInterface;
use Magento\Framework\Indexer\DimensionProviderInterface;
use Magento\Framework\Mview\ActionInterface as MviewActionInterface;
use Magento\Store\Model\StoreDimensionProvider;

class CategoryIndexer implements IndexerActionInterface, MviewActionInterface, DimensionalIndexerInterface
{
private const INDEXER_ID = 'prerender_io_category';
private const DEPLOYMENT_CONFIG_INDEXER_BATCHES = 'indexer/batch_size/';

/** @var DimensionProviderInterface */
private DimensionProviderInterface $dimensionProvider;
/** @var GetUrlsForCategories */
private GetUrlsForCategories $getUrlsForCategories;
/** @var PrerenderClientInterface */
private PrerenderClientInterface $prerenderClient;
/** @var DeploymentConfig */
private DeploymentConfig $eploymentConfig;
/** @var Config */
private Config $prerenderConfigHelper;
/** @var int|null */
private ?int $batchSize;

/**
*
* @param DimensionProviderInterface $dimensionProvider
* @param GetUrlsForCategories $getUrlsForCategories
* @param PrerenderClientInterface $prerenderClient
* @param DeploymentConfig $deploymentConfig
* @param Config $prerenderConfigHelper
* @param int|null $batchSize
*/
public function __construct(
DimensionProviderInterface $dimensionProvider,
GetUrlsForCategories $getUrlsForCategories,
PrerenderClientInterface $prerenderClient,
DeploymentConfig $deploymentConfig,
Config $prerenderConfigHelper,
?int $batchSize = 1000
) {
$this->dimensionProvider = $dimensionProvider;
$this->getUrlsForCategories = $getUrlsForCategories;
$this->prerenderClient = $prerenderClient;
$this->deploymentConfig = $deploymentConfig;
$this->batchSize = $batchSize;
$this->prerenderConfigHelper = $prerenderConfigHelper;
}

/**
* Execute full indexation
*
* @return void
*/
public function executeFull(): void
{
$this->executeList([]);
}

/**
* Execute partial indexation by ID list
*
* @param int[] $ids
* @return void
*/
public function executeList(array $ids): void
{
foreach ($this->dimensionProvider->getIterator() as $dimension) {
try {
$this->executeByDimensions($dimension, new \ArrayIterator($ids));
} catch (FileSystemException|RuntimeException $e) {
continue;
}
}
}

/**
* Execute partial indexation by ID
*
* @param int $id
* @return void
* @throws LocalizedException
*/
public function executeRow($id): void
{
if (!$id) {
throw new LocalizedException(
__('Cannot recache url for an undefined product.')
);
}
$this->executeList([$id]);
}

/**
* Execute materialization on ids entities
*
* @param int[] $ids
* @return void
*/
public function execute($ids): void
{
$this->executeList($ids);
}

/**
* Execute indexing per dimension (store)
*
* @param arry $dimensions
* @param \Traversable $entityIds
* @throws FileSystemException
* @throws RuntimeException
*/
public function executeByDimensions(array $dimensions, \Traversable $entityIds): void
{
if (count($dimensions) > 1 || !isset($dimensions[StoreDimensionProvider::DIMENSION_NAME])) {
throw new \InvalidArgumentException('Indexer "' . self::INDEXER_ID . '" supports only Store dimension');
}
$storeId = (int)$dimensions[StoreDimensionProvider::DIMENSION_NAME]->getValue();

if (!$this->prerenderConfigHelper->isRecacheEnabled($storeId)) {
return;
}

$entityIds = iterator_to_array($entityIds);
// get urls for the products
$urls = $this->getUrlsForCategories->execute($entityIds, $storeId);

$this->batchSize = $this->deploymentConfig->get(
self::DEPLOYMENT_CONFIG_INDEXER_BATCHES . self::INDEXER_ID . '/partial_reindex'
) ?? $this->batchSize;

$urlBatches = array_chunk($urls, $this->batchSize);
foreach ($urlBatches as $batchUrls) {
$this->prerenderClient->recacheUrls($batchUrls, $storeId);
}
}
}
162 changes: 162 additions & 0 deletions Model/Indexer/Category/ProductIndexer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php
/*
* Copyright (c) Aligent Consulting. All rights reserved.
*/

declare(strict_types=1);

namespace Aligent\PrerenderIo\Model\Indexer\Category;

use Aligent\PrerenderIo\Api\PrerenderClientInterface;
use Aligent\PrerenderIo\Helper\Config;
use Aligent\PrerenderIo\Model\Indexer\DataProvider\ProductCategories;
use Aligent\PrerenderIo\Model\Url\GetUrlsForCategories;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\RuntimeException;
use Magento\Framework\Indexer\ActionInterface as IndexerActionInterface;
use Magento\Framework\Indexer\DimensionalIndexerInterface;
use Magento\Framework\Indexer\DimensionProviderInterface;
use Magento\Framework\Mview\ActionInterface as MviewActionInterface;
use Magento\Store\Model\StoreDimensionProvider;

class ProductIndexer implements IndexerActionInterface, MviewActionInterface, DimensionalIndexerInterface
{
private const INDEXER_ID = 'prerender_io_category_product';
private const DEPLOYMENT_CONFIG_INDEXER_BATCHES = 'indexer/batch_size/';

/** @var DimensionProviderInterface */
private DimensionProviderInterface $dimensionProvider;
/** @var ProductCategories */
private ProductCategories $productCategoriesDataProvider;
/** @var GetUrlsForCategories */
private GetUrlsForCategories $getUrlsForCategories;
/** @var PrerenderClientInterface */
private PrerenderClientInterface $prerenderClient;
/** @var DeploymentConfig */
private DeploymentConfig $eploymentConfig;
/** @var Config */
private Config $prerenderConfigHelper;
/** @var int|null */
private ?int $batchSize;

/**
*
* @param DimensionProviderInterface $dimensionProvider
* @param ProductCategories $productCategoriesDataProvider
* @param GetUrlsForCategories $getUrlsForCategories
* @param PrerenderClientInterface $prerenderClient
* @param DeploymentConfig $deploymentConfig
* @param Config $prerenderConfigHelper
* @param int|null $batchSize
*/
public function __construct(
DimensionProviderInterface $dimensionProvider,
ProductCategories $productCategoriesDataProvider,
GetUrlsForCategories $getUrlsForCategories,
PrerenderClientInterface $prerenderClient,
DeploymentConfig $deploymentConfig,
Config $prerenderConfigHelper,
?int $batchSize = 1000
) {
$this->dimensionProvider = $dimensionProvider;
$this->productCategoriesDataProvider = $productCategoriesDataProvider;
$this->getUrlsForCategories = $getUrlsForCategories;
$this->prerenderClient = $prerenderClient;
$this->deploymentConfig = $deploymentConfig;
$this->batchSize = $batchSize;
$this->prerenderConfigHelper = $prerenderConfigHelper;
}

/**
* Execute full indexation
*
* @return void
*/
public function executeFull(): void
{
$this->executeList([]);
}

/**
* Execute partial indexation by ID list
*
* @param int[] $ids
* @return void
*/
public function executeList(array $ids): void
{
foreach ($this->dimensionProvider->getIterator() as $dimension) {
try {
$this->executeByDimensions($dimension, new \ArrayIterator($ids));
} catch (FileSystemException|RuntimeException $e) {
continue;
}
}
}

/**
* Execute partial indexation by ID
*
* @param int $id
* @return void
* @throws LocalizedException
*/
public function executeRow($id): void
{
if (!$id) {
throw new LocalizedException(
__('Cannot recache url for an undefined product.')
);
}
$this->executeList([$id]);
}

/**
* Execute materialization on ids entities
*
* @param int[] $ids
* @return void
*/
public function execute($ids): void
{
$this->executeList($ids);
}

/**
* Execute indexing per dimension (store)
*
* @param arry $dimensions
* @param \Traversable $entityIds
* @throws FileSystemException
* @throws RuntimeException
*/
public function executeByDimensions(array $dimensions, \Traversable $entityIds): void
{
if (count($dimensions) > 1 || !isset($dimensions[StoreDimensionProvider::DIMENSION_NAME])) {
throw new \InvalidArgumentException('Indexer "' . self::INDEXER_ID . '" supports only Store dimension');
}
$storeId = (int)$dimensions[StoreDimensionProvider::DIMENSION_NAME]->getValue();

if (!$this->prerenderConfigHelper->isRecacheEnabled($storeId)) {
return;
}

$entityIds = iterator_to_array($entityIds);
// get list of category ids for the products
$categoryIds = $this->productCategoriesDataProvider->getCategoryIdsForProducts($entityIds, $storeId);

// get urls for the products
$urls = $this->getUrlsForCategories->execute($categoryIds, $storeId);

$this->batchSize = $this->deploymentConfig->get(
self::DEPLOYMENT_CONFIG_INDEXER_BATCHES . self::INDEXER_ID . '/partial_reindex'
) ?? $this->batchSize;

$urlBatches = array_chunk($urls, $this->batchSize);
foreach ($urlBatches as $batchUrls) {
$this->prerenderClient->recacheUrls($batchUrls, $storeId);
}
}
}
62 changes: 62 additions & 0 deletions Model/Indexer/DataProvider/ProductCategories.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/*
* Copyright (c) Aligent Consulting. All rights reserved.
*/

declare(strict_types=1);

namespace Aligent\PrerenderIo\Model\Indexer\DataProvider;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;

class ProductCategories
{
/** @var ProductCollectionFactory */
private ProductCollectionFactory $productCollectionFactory;
/** @var CategoryCollectionFactory */
private CategoryCollectionFactory $categoryCollectionFactory;

/**
* @param ProductCollectionFactory $productCollectionFactory
* @param CategoryCollectionFactory $categoryCollectionFactory
*/
public function __construct(
ProductCollectionFactory $productCollectionFactory,
CategoryCollectionFactory $categoryCollectionFactory
) {
$this->productCollectionFactory = $productCollectionFactory;
$this->categoryCollectionFactory = $categoryCollectionFactory;
}

/**
* Get complete list of categories containing one or more of the given products
*
* @param array $productIds
* @param int $storeId
* @return array
*/
public function getCategoryIdsForProducts(array $productIds, int $storeId): array
{
// if array of product ids is empty, just load all categories
if (empty($productIds)) {
$categoryCollection = $this->categoryCollectionFactory->create();
$categoryCollection->setStoreId($storeId);
return $categoryCollection->getAllIds();
}

$productCollection = $this->productCollectionFactory->create();
$productCollection->addIdFilter($productIds);
$productCollection->setStoreId($storeId);
// add category information
$productCollection->addCategoryIds();

$categoryIds = [];
/** @var Product $product */
foreach ($productCollection->getItems() as $product) {
$categoryIds[] = $product->getCategoryIds();
}
return array_unique(array_merge(...$categoryIds));
}
}
2 changes: 1 addition & 1 deletion Model/Indexer/Product/ProductIndexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use Aligent\PrerenderIo\Api\PrerenderClientInterface;
use Aligent\PrerenderIo\Helper\Config;
use Aligent\PrerenderIo\Model\Product\GetUrlsForProducts;
use Aligent\PrerenderIo\Model\Url\GetUrlsForProducts;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
Expand Down
Loading

0 comments on commit 959f78f

Please sign in to comment.