Skip to content

Commit

Permalink
FRW-8958 Improved product abstract publishing performance by avoiding…
Browse files Browse the repository at this point in the history
… joining concretes. (#11114)

FRW-8958 Improved product abstract publishing performance by avoiding joining concretes.
  • Loading branch information
spryker-release-bot authored Oct 2, 2024
1 parent d133506 commit 237d8c9
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
/**
* @method \Spryker\Zed\ProductStorage\ProductStorageConfig getConfig()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageQueryContainerInterface getQueryContainer()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface getRepository()
*/
class ProductStorageBusinessFactory extends AbstractBusinessFactory
{
Expand All @@ -32,6 +33,7 @@ public function createProductAbstractStorageWriter()
$this->createAttributeMap(),
$this->getQueryContainer(),
$this->getStoreFacade(),
$this->getRepository(),
$this->getConfig()->isSendingToQueue(),
$this->getProductAbstractStorageExpanderPlugins(),
$this->getProductAbstractStorageCollectionFilterPlugins(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

/**
* @method \Spryker\Zed\ProductStorage\Business\ProductStorageBusinessFactory getFactory()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface getRepository()
*/
class ProductStorageFacade extends AbstractFacade implements ProductStorageFacadeInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Spryker\Zed\ProductStorage\Dependency\Facade\ProductStorageToProductInterface;
use Spryker\Zed\ProductStorage\Dependency\Facade\ProductStorageToStoreFacadeInterface;
use Spryker\Zed\ProductStorage\Persistence\ProductStorageQueryContainerInterface;
use Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface;

class ProductAbstractStorageWriter implements ProductAbstractStorageWriterInterface
{
Expand Down Expand Up @@ -52,6 +53,11 @@ class ProductAbstractStorageWriter implements ProductAbstractStorageWriterInterf
*/
public const STORE_NAME = 'STORE_NAME';

/**
* @var string
*/
protected const COL_PRODUCT_COUNT = 'productCount';

/**
* @var \Spryker\Zed\ProductStorage\Dependency\Facade\ProductStorageToProductInterface
*/
Expand All @@ -72,6 +78,11 @@ class ProductAbstractStorageWriter implements ProductAbstractStorageWriterInterf
*/
protected $storeFacade;

/**
* @var \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface
*/
protected ProductStorageRepositoryInterface $productStorageRepository;

/**
* @deprecated Use {@link \Spryker\Zed\SynchronizationBehavior\SynchronizationBehaviorConfig::isSynchronizationEnabled()} instead.
*
Expand All @@ -94,11 +105,17 @@ class ProductAbstractStorageWriter implements ProductAbstractStorageWriterInterf
*/
protected $productAbstractStorageCollectionFilterPlugins = [];

/**
* @var array<int, bool>
*/
protected static array $activeConcretesInAbstractMap = [];

/**
* @param \Spryker\Zed\ProductStorage\Dependency\Facade\ProductStorageToProductInterface $productFacade
* @param \Spryker\Zed\ProductStorage\Business\Attribute\AttributeMapInterface $attributeMap
* @param \Spryker\Zed\ProductStorage\Persistence\ProductStorageQueryContainerInterface $queryContainer
* @param \Spryker\Zed\ProductStorage\Dependency\Facade\ProductStorageToStoreFacadeInterface $storeFacade
* @param \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface $productStorageRepository
* @param bool $isSendingToQueue
* @param array<\Spryker\Zed\ProductStorageExtension\Dependency\Plugin\ProductAbstractStorageExpanderPluginInterface> $productAbstractStorageExpanderPlugins
* @param array<\Spryker\Zed\ProductStorageExtension\Dependency\Plugin\ProductAbstractStorageCollectionFilterPluginInterface> $productAbstractStorageCollectionFilterPlugins
Expand All @@ -108,6 +125,7 @@ public function __construct(
AttributeMapInterface $attributeMap,
ProductStorageQueryContainerInterface $queryContainer,
ProductStorageToStoreFacadeInterface $storeFacade,
ProductStorageRepositoryInterface $productStorageRepository,
$isSendingToQueue,
array $productAbstractStorageExpanderPlugins,
array $productAbstractStorageCollectionFilterPlugins
Expand All @@ -119,6 +137,7 @@ public function __construct(
$this->isSendingToQueue = $isSendingToQueue;
$this->productAbstractStorageExpanderPlugins = $productAbstractStorageExpanderPlugins;
$this->productAbstractStorageCollectionFilterPlugins = $productAbstractStorageCollectionFilterPlugins;
$this->productStorageRepository = $productStorageRepository;
}

/**
Expand All @@ -128,7 +147,7 @@ public function __construct(
*/
public function publish(array $productAbstractIds)
{
$productAbstractLocalizedEntities = $this->findProductAbstractLocalizedEntities($productAbstractIds);
$productAbstractLocalizedEntities = $this->productStorageRepository->getProductAbstractsByIds($productAbstractIds);
$productAbstractStorageEntities = $this->findProductAbstractStorageEntities($productAbstractIds);

if (!$productAbstractLocalizedEntities) {
Expand Down Expand Up @@ -200,12 +219,20 @@ protected function storeData(array $productAbstractLocalizedEntities, array $pro
);
$productAbstractStorageTransfers = $this->executeProductAbstractStorageFilterPlugins($productAbstractStorageTransfers);
$indexedProductAbstractStorageTransfers = $this->indexProductAbstractStorageTransfersByIdProductAbstract($productAbstractStorageTransfers);
$idProductAbstracts = [];

foreach ($pairedEntities as $pair) {
$productAbstractLocalizedEntity = $pair[static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY];
$idProductAbstracts[] = $productAbstractLocalizedEntity[static::COL_FK_PRODUCT_ABSTRACT];
}

$concreteProductCountMap = $this->productStorageRepository->getProductConcretesCountByIdProductAbstracts($idProductAbstracts);

foreach ($pairedEntities as $pair) {
$productAbstractLocalizedEntity = $pair[static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY];
$productAbstractStorageEntity = $pair[static::PRODUCT_ABSTRACT_STORAGE_ENTITY];

if ($productAbstractLocalizedEntity === null || !$this->isActive($productAbstractLocalizedEntity)) {
if ($productAbstractLocalizedEntity === null || !$this->isActive($productAbstractLocalizedEntity, $concreteProductCountMap)) {
$this->deleteProductAbstractStorageEntity($productAbstractStorageEntity);

continue;
Expand Down Expand Up @@ -371,14 +398,17 @@ protected function storeProductAbstractStorageEntity(

/**
* @param array $productAbstractLocalizedEntity
* @param array<array<string, int>> $productConcreteCountMap
*
* @return bool
*/
protected function isActive(array $productAbstractLocalizedEntity)
protected function isActive(array $productAbstractLocalizedEntity, array $productConcreteCountMap)
{
foreach ($productAbstractLocalizedEntity['SpyProductAbstract']['SpyProducts'] as $productEntity) {
if ($productEntity['is_active']) {
return true;
$idProductAbstract = $productAbstractLocalizedEntity[static::COL_FK_PRODUCT_ABSTRACT];

foreach ($productConcreteCountMap as $item) {
if ($item[static::COL_FK_PRODUCT_ABSTRACT] === $idProductAbstract) {
return $item[static::COL_PRODUCT_COUNT] > 0;
}
}

Expand Down Expand Up @@ -513,16 +543,6 @@ protected function filterSuperAttributeKeys(array $attributes)
return array_keys($superAttributes);
}

/**
* @param array<int> $productAbstractIds
*
* @return array
*/
protected function findProductAbstractLocalizedEntities(array $productAbstractIds)
{
return $this->queryContainer->queryProductAbstractByIds($productAbstractIds)->find()->getData();
}

/**
* @param array<int> $productAbstractIds
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageQueryContainerInterface getQueryContainer()
* @method \Spryker\Zed\ProductStorage\ProductStorageConfig getConfig()
* @method \Spryker\Zed\ProductStorage\Business\ProductStorageFacadeInterface getFacade()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface getRepository()
*/
class ProductStorageCommunicationFactory extends AbstractCommunicationFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace Spryker\Zed\ProductStorage\Persistence;

use Orm\Zed\Product\Persistence\SpyProductAbstractLocalizedAttributesQuery;
use Orm\Zed\Product\Persistence\SpyProductQuery;
use Orm\Zed\ProductStorage\Persistence\SpyProductAbstractStorageQuery;
use Orm\Zed\ProductStorage\Persistence\SpyProductConcreteStorageQuery;
use Spryker\Zed\Kernel\Persistence\AbstractPersistenceFactory;
Expand All @@ -15,6 +17,7 @@
/**
* @method \Spryker\Zed\ProductStorage\ProductStorageConfig getConfig()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageQueryContainerInterface getQueryContainer()
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepositoryInterface getRepository()
*/
class ProductStoragePersistenceFactory extends AbstractPersistenceFactory
{
Expand All @@ -41,4 +44,20 @@ public function getProductQueryContainer()
{
return $this->getProvidedDependency(ProductStorageDependencyProvider::QUERY_CONTAINER_PRODUCT);
}

/**
* @return \Orm\Zed\Product\Persistence\SpyProductQuery
*/
public function getProductPropelQuery(): SpyProductQuery
{
return $this->getProvidedDependency(ProductStorageDependencyProvider::PROPEL_QUERY_PRODUCT);
}

/**
* @return \Orm\Zed\Product\Persistence\SpyProductAbstractLocalizedAttributesQuery
*/
public function getProductAbstractLocalizedAttributesPropelQuery(): SpyProductAbstractLocalizedAttributesQuery
{
return $this->getProvidedDependency(ProductStorageDependencyProvider::PROPEL_QUERY_PRODUCT_ABSTRACT_LOCALIZED_ATTRIBUTES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class ProductStorageQueryContainer extends AbstractQueryContainer implements Pro
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepository::getProductAbstractsByIds()} for better performance.
*
* @param array<int> $productAbstractIds
*
* @return \Orm\Zed\Product\Persistence\SpyProductAbstractLocalizedAttributesQuery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ interface ProductStorageQueryContainerInterface extends QueryContainerInterface
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductStorage\Persistence\ProductStorageRepository::getProductAbstractsByIds()} for better performance.
*
* @param array<int> $productAbstractIds
*
* @return \Orm\Zed\Product\Persistence\SpyProductAbstractLocalizedAttributesQuery
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

/**
* Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
*/

namespace Spryker\Zed\ProductStorage\Persistence;

use Orm\Zed\Product\Persistence\Map\SpyProductAbstractLocalizedAttributesTableMap;
use Orm\Zed\Url\Persistence\Map\SpyUrlTableMap;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Spryker\Zed\Kernel\Persistence\AbstractRepository;

/**
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStoragePersistenceFactory getFactory()
*/
class ProductStorageRepository extends AbstractRepository implements ProductStorageRepositoryInterface
{
/**
* @var string
*/
protected const URL_RELATION = 'SpyProductAbstract.SpyUrl';

/**
* @var string
*/
protected const COLUMN_URL = 'url';

/**
* @var string
*/
protected const ENTITY_URL = 'SpyUrl';

/**
* @var string
*/
protected const COL_PRODUCT_COUNT = 'productCount';

/**
* @var string
*/
protected const COL_FK_PRODUCT_ABSTRACT = 'fk_product_abstract';

/**
* @param array<int> $productAbstractIds
*
* @return array<int|string|bool>
*/
public function getProductAbstractsByIds(array $productAbstractIds): array
{
return $this->getFactory()->getProductAbstractLocalizedAttributesPropelQuery()
->joinWithLocale()
->joinWithSpyProductAbstract()
->useSpyProductAbstractQuery()
->joinWithSpyProductAbstractStore()
->useSpyProductAbstractStoreQuery()
->joinWithSpyStore()
->endUse()
->endUse()
->filterByFkProductAbstract_In($productAbstractIds)
->setFormatter(ModelCriteria::FORMAT_ARRAY)
->join(static::URL_RELATION)
->addJoinCondition(static::ENTITY_URL, sprintf('%s = %s', SpyUrlTableMap::COL_FK_LOCALE, SpyProductAbstractLocalizedAttributesTableMap::COL_FK_LOCALE))
->withColumn(SpyUrlTableMap::COL_URL, static::COLUMN_URL)
->find()
->getData();
}

/**
* @param array<int> $idProductAbstracts
*
* @return array<array<string, int>>
*/
public function getProductConcretesCountByIdProductAbstracts(array $idProductAbstracts): array
{
/** @var \Propel\Runtime\Collection\ObjectCollection $productConcretesCollection */
$productConcretesCollection = $this->getFactory()->getProductPropelQuery()
->filterByFkProductAbstract_In($idProductAbstracts)
->filterByIsActive(true)
->withColumn('COUNT(*)', static::COL_PRODUCT_COUNT)
->select([static::COL_FK_PRODUCT_ABSTRACT, static::COL_PRODUCT_COUNT])
->groupByFkProductAbstract()
->find();

return $productConcretesCollection->toArray();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
*/

namespace Spryker\Zed\ProductStorage\Persistence;

/**
* @method \Spryker\Zed\ProductStorage\Persistence\ProductStoragePersistenceFactory getFactory()
*/
interface ProductStorageRepositoryInterface
{
/**
* @param array<int> $productAbstractIds
*
* @return array<mixed>
*/
public function getProductAbstractsByIds(array $productAbstractIds): array;

/**
* @param array<int> $idProductAbstract
*
* @return array<array<string, int>>
*/
public function getProductConcretesCountByIdProductAbstracts(array $idProductAbstract): array;
}
Loading

0 comments on commit 237d8c9

Please sign in to comment.