Skip to content

Commit

Permalink
CC-31551 Fixed performance issue in product search attribute fetching…
Browse files Browse the repository at this point in the history
…. (#10630)

CC-31551 Fixed performance issue in product search attribute fetching.
  • Loading branch information
artem-png committed Nov 27, 2023
1 parent cb7a403 commit a1ae429
Show file tree
Hide file tree
Showing 24 changed files with 830 additions and 11 deletions.
7 changes: 7 additions & 0 deletions architecture-baseline.json
Expand Up @@ -181,6 +181,13 @@
"ruleset": "Spryker",
"priority": "2"
},
{
"fileName": "src/Spryker/Zed/ProductSearch/Dependency/Facade/ProductSearchToGlossaryBridge.php",
"description": "Bridges: Method `getTranslationsByGlossaryKeysAndLocaleTransfers()` must have `public function get<DomainEntity>Collection(<DomainEntity>CriteriaTransfer): <DomainEntity>CollectionTransfer` signature.",
"rule": "BridgeFacadeMethodsRule",
"ruleset": "Spryker",
"priority": "2"
},
{
"fileName": "src/Spryker/Zed/ProductSearch/Dependency/Facade/ProductSearchToGlossaryInterface.php",
"description": "Bridges: The bridge interface has incorrect method signature for `createAndTouchTranslation()`. Missed return type. That violates the rule \"All bridge interface methods must have exactly the same or more strict signature as their parent\"",
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -8,7 +8,7 @@
"spryker/acl-merchant-portal-extension": "^1.0.0",
"spryker/collector": "^5.1.1 || ^6.0.0",
"spryker/event": "^2.1.0",
"spryker/glossary": "^3.0.0",
"spryker/glossary": "^3.16.0",
"spryker/gui": "^3.33.0",
"spryker/kernel": "^3.30.0",
"spryker/key-builder": "^1.1.0",
Expand All @@ -22,7 +22,7 @@
"spryker/store": "^1.4.0",
"spryker/symfony": "^3.0.0",
"spryker/touch": "^3.0.0 || ^4.0.0",
"spryker/transfer": "^3.25.0",
"spryker/transfer": "^3.27.0",
"spryker/util-data-reader": "^1.0.0"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion dependency.json
@@ -1,5 +1,5 @@
{
"include": {
"spryker/transfer": "Provides transfer objects decimal property type functionality."
"spryker/transfer": "Provides transfer objects definition with strict types."
}
}
Expand Up @@ -67,6 +67,8 @@

<transfer name="Translation">
<property name="value" type="string"/>
<property name="glossaryKey" type="GlossaryKey" strict="true"/>
<property name="fkLocale" type="int"/>
</transfer>

<transfer name="PageMap">
Expand Down Expand Up @@ -94,4 +96,27 @@
<property name="collection" type="array" singular="aclEntityMetadata" associative="true"/>
</transfer>

<transfer name="ProductSearchAttributeCollection" strict="true">
<property name="productSearchAttributes" type="ProductSearchAttribute[]" singular="productSearchAttribute"/>
</transfer>

<transfer name="ProductSearchAttributeCriteria" strict="true">
<property name="productSearchAttributeConditions" type="ProductSearchAttributeConditions"/>
<property name="sortCollection" type="Sort[]" singular="sort"/>
</transfer>

<transfer name="ProductSearchAttributeConditions" strict="true">
<property name="productSearchAttributeIds" type="int[]" singular="idProductSearchAttribute"/>
<property name="withLocalizedAttributes" type="bool"/>
</transfer>

<transfer name="Sort">
<property name="field" type="string"/>
<property name="isAscending" type="bool"/>
</transfer>

<transfer name="GlossaryKey">
<property name="key" type="string"/>
</transfer>

</transfers>
@@ -0,0 +1,132 @@
<?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\ProductSearch\Business\Expander;

use Generated\Shared\Transfer\LocalizedProductSearchAttributeKeyTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeTransfer;
use Spryker\Shared\ProductSearch\Code\KeyBuilder\GlossaryKeyBuilderInterface;
use Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToGlossaryInterface;
use Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToLocaleInterface;

class LocalizedProductSearchAttributeKeyExpander implements LocalizedProductSearchAttributeKeyExpanderInterface
{
/**
* @var \Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToLocaleInterface
*/
protected ProductSearchToLocaleInterface $localeFacade;

/**
* @var \Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToGlossaryInterface
*/
protected ProductSearchToGlossaryInterface $glossaryFacade;

/**
* @var \Spryker\Shared\ProductSearch\Code\KeyBuilder\GlossaryKeyBuilderInterface
*/
protected GlossaryKeyBuilderInterface $glossaryKeyBuilder;

/**
* @param \Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToLocaleInterface $localeFacade
* @param \Spryker\Zed\ProductSearch\Dependency\Facade\ProductSearchToGlossaryInterface $glossaryFacade
* @param \Spryker\Shared\ProductSearch\Code\KeyBuilder\GlossaryKeyBuilderInterface $glossaryKeyBuilder
*/
public function __construct(
ProductSearchToLocaleInterface $localeFacade,
ProductSearchToGlossaryInterface $glossaryFacade,
GlossaryKeyBuilderInterface $glossaryKeyBuilder
) {
$this->localeFacade = $localeFacade;
$this->glossaryFacade = $glossaryFacade;
$this->glossaryKeyBuilder = $glossaryKeyBuilder;
}

/**
* @param \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer
*/
public function expandProductSearchAttributeCollectionWithLocalizedKeys(
ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
): ProductSearchAttributeCollectionTransfer {
$localeTransfers = $this->localeFacade->getLocaleCollection();
$glossaryKeys = $this->extractGlossaryKeysFromProductSearchAttributeCollectionTransfer($productSearchAttributeCollectionTransfer);

$translationTransfers = $this->glossaryFacade->getTranslationsByGlossaryKeysAndLocaleTransfers($glossaryKeys, $localeTransfers);
$translationsIndexedByKeyAndLocale = $this->getTranslationValuesIndexedByGlossaryKeyAndLocale($translationTransfers);

foreach ($productSearchAttributeCollectionTransfer->getProductSearchAttributes() as $productSearchAttributeTransfer) {
$this->expandProductSearchAttributeWithLocalizedKeys($localeTransfers, $translationsIndexedByKeyAndLocale, $productSearchAttributeTransfer);
}

return $productSearchAttributeCollectionTransfer;
}

/**
* @param list<\Generated\Shared\Transfer\LocaleTransfer> $localeTransfers
* @param array<int, array<string, string>> $translationsIndexedByKeyAndLocale
* @param \Generated\Shared\Transfer\ProductSearchAttributeTransfer $productSearchAttributeTransfer
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeTransfer
*/
protected function expandProductSearchAttributeWithLocalizedKeys(
array $localeTransfers,
array $translationsIndexedByKeyAndLocale,
ProductSearchAttributeTransfer $productSearchAttributeTransfer
): ProductSearchAttributeTransfer {
foreach ($localeTransfers as $localeTransfer) {
$translation = $translationsIndexedByKeyAndLocale[$localeTransfer->getIdLocaleOrFail()][$productSearchAttributeTransfer->getKeyOrFail()] ?? null;
$localizedProductSearchAttributeKeyTransfer = new LocalizedProductSearchAttributeKeyTransfer();
$localizedProductSearchAttributeKeyTransfer
->setLocaleName($localeTransfer->getLocaleNameOrFail())
->setKeyTranslation($translation);

$productSearchAttributeTransfer->addLocalizedKey($localizedProductSearchAttributeKeyTransfer);
}

return $productSearchAttributeTransfer;
}

/**
* @param list<\Generated\Shared\Transfer\TranslationTransfer> $translationTransfers
*
* @return array<int, array<string, string>>
*/
protected function getTranslationValuesIndexedByGlossaryKeyAndLocale(array $translationTransfers): array
{
$translationsIndexedByKeyAndLocale = [];

foreach ($translationTransfers as $translationTransfer) {
$key = $translationTransfer->getGlossaryKeyOrFail()->getKeyOrFail();
$translationsIndexedByKeyAndLocale[$translationTransfer->getFkLocaleOrFail()][$key] = $translationTransfer->getValueOrFail();
}

return $translationsIndexedByKeyAndLocale;
}

/**
* @param \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
*
* @return list<string>
*/
protected function extractGlossaryKeysFromProductSearchAttributeCollectionTransfer(
ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
): array {
$glossaryKeys = [];

foreach ($productSearchAttributeCollectionTransfer->getProductSearchAttributes() as $productSearchAttributeTransfer) {
if (!$productSearchAttributeTransfer->getKey()) {
continue;
}

$glossaryKeys[] = $productSearchAttributeTransfer->getKeyOrFail();
}

return $glossaryKeys;
}
}
@@ -0,0 +1,22 @@
<?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\ProductSearch\Business\Expander;

use Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer;

interface LocalizedProductSearchAttributeKeyExpanderInterface
{
/**
* @param \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer
*/
public function expandProductSearchAttributeCollectionWithLocalizedKeys(
ProductSearchAttributeCollectionTransfer $productSearchAttributeCollectionTransfer
): ProductSearchAttributeCollectionTransfer;
}
Expand Up @@ -16,6 +16,8 @@
use Spryker\Zed\ProductSearch\Business\Collector\ProductSearchCollectorRunner;
use Spryker\Zed\ProductSearch\Business\Collector\ProductSearchCollectorRunnerInterface;
use Spryker\Zed\ProductSearch\Business\Collector\Storage\ProductSearchConfigExtensionCollector;
use Spryker\Zed\ProductSearch\Business\Expander\LocalizedProductSearchAttributeKeyExpander;
use Spryker\Zed\ProductSearch\Business\Expander\LocalizedProductSearchAttributeKeyExpanderInterface;
use Spryker\Zed\ProductSearch\Business\Map\Collector\ProductSearchAttributeCollector;
use Spryker\Zed\ProductSearch\Business\Map\Collector\ProductSearchAttributeMapCollector;
use Spryker\Zed\ProductSearch\Business\Map\ProductSearchAttributeMapper;
Expand All @@ -26,6 +28,8 @@
use Spryker\Zed\ProductSearch\Business\Model\ProductAbstractSearchReader;
use Spryker\Zed\ProductSearch\Business\Model\ProductConcreteSearchReader;
use Spryker\Zed\ProductSearch\Business\Model\ProductSearchWriter;
use Spryker\Zed\ProductSearch\Business\Reader\ProductSearchAttributeReader;
use Spryker\Zed\ProductSearch\Business\Reader\ProductSearchAttributeReaderInterface;
use Spryker\Zed\ProductSearch\Business\Transfer\ProductAttributeTransferMapper;
use Spryker\Zed\ProductSearch\Persistence\Collector\Propel\ProductSearchConfigExtensionCollectorQuery;
use Spryker\Zed\ProductSearch\ProductSearchDependencyProvider;
Expand Down Expand Up @@ -61,6 +65,29 @@ public function createProductSearchAttributeMapper()
return new ProductSearchAttributeMapper($this->getAttributeMapCollectors());
}

/**
* @return \Spryker\Zed\ProductSearch\Business\Expander\LocalizedProductSearchAttributeKeyExpanderInterface
*/
public function createLocalizedProductSearchAttributeKeyExpander(): LocalizedProductSearchAttributeKeyExpanderInterface
{
return new LocalizedProductSearchAttributeKeyExpander(
$this->getLocaleFacade(),
$this->getGlossaryFacade(),
$this->createFilterGlossaryKeyBuilder(),
);
}

/**
* @return \Spryker\Zed\ProductSearch\Business\Reader\ProductSearchAttributeReaderInterface
*/
public function createProductSearchAttributeReader(): ProductSearchAttributeReaderInterface
{
return new ProductSearchAttributeReader(
$this->getRepository(),
$this->createLocalizedProductSearchAttributeKeyExpander(),
);
}

/**
* @return array<\Spryker\Zed\ProductSearch\Business\Map\Collector\ProductSearchAttributeMapCollectorInterface>
*/
Expand Down
23 changes: 23 additions & 0 deletions src/Spryker/Zed/ProductSearch/Business/ProductSearchFacade.php
Expand Up @@ -10,6 +10,8 @@
use Generated\Shared\Transfer\LocaleTransfer;
use Generated\Shared\Transfer\PageMapTransfer;
use Generated\Shared\Transfer\ProductConcreteTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeCriteriaTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeTransfer;
use Generated\Shared\Transfer\ProductSearchPreferencesTransfer;
use Orm\Zed\Touch\Persistence\SpyTouchQuery;
Expand Down Expand Up @@ -263,6 +265,8 @@ public function deleteProductSearchAttribute(ProductSearchAttributeTransfer $pro
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductSearch\Business\ProductSearchFacade::getProductSearchAttributeCollection()} instead.
*
* @param int $idProductSearchAttribute
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeTransfer|null
Expand All @@ -280,6 +284,8 @@ public function getProductSearchAttribute($idProductSearchAttribute)
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductSearch\Business\ProductSearchFacade::getProductSearchAttributeCollection()} instead.
*
* @return array<\Generated\Shared\Transfer\ProductSearchAttributeTransfer>
*/
public function getProductSearchAttributeList()
Expand All @@ -290,6 +296,23 @@ public function getProductSearchAttributeList()
->getAttributeList();
}

/**
* {@inheritDoc}
*
* @api
*
* @param \Generated\Shared\Transfer\ProductSearchAttributeCriteriaTransfer $productSearchAttributeCriteriaTransfer
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer
*/
public function getProductSearchAttributeCollection(
ProductSearchAttributeCriteriaTransfer $productSearchAttributeCriteriaTransfer
): ProductSearchAttributeCollectionTransfer {
return $this->getFactory()
->createProductSearchAttributeReader()
->getProductSearchAttributeCollection($productSearchAttributeCriteriaTransfer);
}

/**
* {@inheritDoc}
*
Expand Down
Expand Up @@ -10,6 +10,8 @@
use Generated\Shared\Transfer\LocaleTransfer;
use Generated\Shared\Transfer\PageMapTransfer;
use Generated\Shared\Transfer\ProductConcreteTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeCriteriaTransfer;
use Generated\Shared\Transfer\ProductSearchAttributeTransfer;
use Generated\Shared\Transfer\ProductSearchPreferencesTransfer;
use Orm\Zed\Touch\Persistence\SpyTouchQuery;
Expand Down Expand Up @@ -218,6 +220,8 @@ public function deleteProductSearchAttribute(ProductSearchAttributeTransfer $pro
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductSearch\Business\ProductSearchFacadeInterface::getProductSearchAttributeCollection()} instead.
*
* @param int $idProductSearchAttribute
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeTransfer|null
Expand All @@ -231,10 +235,31 @@ public function getProductSearchAttribute($idProductSearchAttribute);
*
* @api
*
* @deprecated Use {@link \Spryker\Zed\ProductSearch\Business\ProductSearchFacadeInterface::getProductSearchAttributeCollection()} instead.
*
* @return array<\Generated\Shared\Transfer\ProductSearchAttributeTransfer>
*/
public function getProductSearchAttributeList();

/**
* Specification:
* - Retrieves product search attribute entities filtered by criteria from Persistence.
* - Uses `ProductSearchAttributeCriteriaTransfer.productSearchAttributeConditions.productSearchAttributeIds` to filter by product search attribute ids.
* - Uses `ProductSearchAttributeCriteriaTransfer.sort.field` to set the 'order by' field.
* - Uses `ProductSearchAttributeCriteriaTransfer.sort.isAscending` to set ascending/descending order.
* - Uses `ProductSearchAttributeCriteriaTransfer.productSearchAttributeConditions.withLocalizedAttributes` to load localized attributes.
* - Returns `ProductSearchAttributeCollectionTransfer` filled with found product search attributes.
*
* @api
*
* @param \Generated\Shared\Transfer\ProductSearchAttributeCriteriaTransfer $productSearchAttributeCriteriaTransfer
*
* @return \Generated\Shared\Transfer\ProductSearchAttributeCollectionTransfer
*/
public function getProductSearchAttributeCollection(
ProductSearchAttributeCriteriaTransfer $productSearchAttributeCriteriaTransfer
): ProductSearchAttributeCollectionTransfer;

/**
* Specification:
* - Updates the positions of the provided product search attribute entities.
Expand Down

0 comments on commit a1ae429

Please sign in to comment.