-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2415 from magento-performance/MAGETWO-90564
[PERFORMANCE] Catalog Rule indexer matching mechanism optimization
- Loading branch information
Showing
26 changed files
with
4,153 additions
and
9 deletions.
There are no files selected for viewing
131 changes: 131 additions & 0 deletions
131
...riteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/EavAttributeCondition.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\ConditionBuilder; | ||
|
||
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionInterface; | ||
use Magento\Framework\Api\Filter; | ||
use Magento\Catalog\Model\ResourceModel\Product\Collection; | ||
use Magento\Catalog\Model\ResourceModel\Eav\Attribute; | ||
|
||
/** | ||
* Based on Magento\Framework\Api\Filter builds condition | ||
* that can be applied to Catalog\Model\ResourceModel\Product\Collection | ||
* to filter products that has specific value for EAV attribute | ||
*/ | ||
class EavAttributeCondition implements CustomConditionInterface | ||
{ | ||
/** | ||
* @var \Magento\Framework\App\ResourceConnection | ||
*/ | ||
private $resourceConnection; | ||
|
||
/** | ||
* @var \Magento\Eav\Model\Config | ||
*/ | ||
private $eavConfig; | ||
|
||
/** | ||
* @param \Magento\Eav\Model\Config $eavConfig | ||
* @param \Magento\Framework\App\ResourceConnection $resourceConnection | ||
*/ | ||
public function __construct( | ||
\Magento\Eav\Model\Config $eavConfig, | ||
\Magento\Framework\App\ResourceConnection $resourceConnection | ||
) { | ||
$this->eavConfig = $eavConfig; | ||
$this->resourceConnection = $resourceConnection; | ||
} | ||
|
||
/** | ||
* Build condition to filter product collection by EAV attribute | ||
* | ||
* @param Filter $filter | ||
* @return string | ||
* @throws \DomainException | ||
* @throws \Magento\Framework\Exception\LocalizedException | ||
*/ | ||
public function build(Filter $filter): string | ||
{ | ||
$attribute = $this->getAttributeByCode($filter->getField()); | ||
$tableAlias = 'ca_' . $attribute->getAttributeCode(); | ||
|
||
$conditionType = $this->mapConditionType($filter->getConditionType()); | ||
$conditionValue = $this->mapConditionValue($conditionType, $filter->getValue()); | ||
|
||
// NOTE: store scope was ignored intentionally to perform search across all stores | ||
$attributeSelect = $this->resourceConnection->getConnection() | ||
->select() | ||
->from( | ||
[$tableAlias => $attribute->getBackendTable()], | ||
$tableAlias . '.' . $attribute->getEntityIdField() | ||
)->where( | ||
$this->resourceConnection->getConnection()->prepareSqlCondition( | ||
$tableAlias . '.' . $attribute->getIdFieldName(), | ||
['eq' => $attribute->getAttributeId()] | ||
) | ||
)->where( | ||
$this->resourceConnection->getConnection()->prepareSqlCondition( | ||
$tableAlias . '.value', | ||
[$conditionType => $conditionValue] | ||
) | ||
); | ||
|
||
return $this->resourceConnection | ||
->getConnection() | ||
->prepareSqlCondition( | ||
Collection::MAIN_TABLE_ALIAS . '.' . $attribute->getEntityIdField(), | ||
[ | ||
'in' => $attributeSelect | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* @param string $field | ||
* @return Attribute | ||
* @throws \Magento\Framework\Exception\LocalizedException | ||
*/ | ||
private function getAttributeByCode(string $field): Attribute | ||
{ | ||
return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field); | ||
} | ||
|
||
/** | ||
* Map equal and not equal conditions to in and not in | ||
* | ||
* @param string $conditionType | ||
* @return mixed | ||
*/ | ||
private function mapConditionType(string $conditionType): string | ||
{ | ||
$conditionsMap = [ | ||
'eq' => 'in', | ||
'neq' => 'nin' | ||
]; | ||
|
||
return isset($conditionsMap[$conditionType]) ? $conditionsMap[$conditionType] : $conditionType; | ||
} | ||
|
||
/** | ||
* Wraps value with '%' if condition type is 'like' or 'not like' | ||
* | ||
* @param string $conditionType | ||
* @param string $conditionValue | ||
* @return string | ||
*/ | ||
private function mapConditionValue(string $conditionType, string $conditionValue): string | ||
{ | ||
$conditionsMap = ['like', 'nlike']; | ||
|
||
if (in_array($conditionType, $conditionsMap)) { | ||
$conditionValue = '%' . $conditionValue . '%'; | ||
} | ||
|
||
return $conditionValue; | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
...el/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/Factory.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\ConditionBuilder; | ||
|
||
use Magento\Framework\Api\Filter; | ||
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionInterface; | ||
use Magento\Catalog\Model\ResourceModel\Eav\Attribute; | ||
|
||
/** | ||
* Creates appropriate condition builder based on filter field | ||
* - native attribute condition builder if filter field is native attribute in product | ||
* - eav condition builder if filter field is eav attribute | ||
*/ | ||
class Factory | ||
{ | ||
/** | ||
* @var \Magento\Eav\Model\Config | ||
*/ | ||
private $eavConfig; | ||
|
||
/** | ||
* @var \Magento\Catalog\Model\ResourceModel\Product | ||
*/ | ||
private $productResource; | ||
|
||
/** | ||
* @var CustomConditionInterface | ||
*/ | ||
private $eavAttributeConditionBuilder; | ||
|
||
/** | ||
* @var CustomConditionInterface | ||
*/ | ||
private $nativeAttributeConditionBuilder; | ||
|
||
/** | ||
* @param \Magento\Eav\Model\Config $eavConfig | ||
* @param \Magento\Catalog\Model\ResourceModel\Product $productResource | ||
* @param CustomConditionInterface $eavAttributeConditionBuilder | ||
* @param CustomConditionInterface $nativeAttributeConditionBuilder | ||
*/ | ||
public function __construct( | ||
\Magento\Eav\Model\Config $eavConfig, | ||
\Magento\Catalog\Model\ResourceModel\Product $productResource, | ||
CustomConditionInterface $eavAttributeConditionBuilder, | ||
CustomConditionInterface $nativeAttributeConditionBuilder | ||
) { | ||
$this->eavConfig = $eavConfig; | ||
$this->productResource = $productResource; | ||
$this->eavAttributeConditionBuilder = $eavAttributeConditionBuilder; | ||
$this->nativeAttributeConditionBuilder = $nativeAttributeConditionBuilder; | ||
} | ||
|
||
/** | ||
* Decides which condition builder should be used for passed filter | ||
* can be either EAV attribute builder or native attribute builder | ||
* "native" attribute means attribute that is in catalog_product_entity table | ||
* | ||
* @param Filter $filter | ||
* @return CustomConditionInterface | ||
* @throws \Magento\Framework\Exception\LocalizedException | ||
*/ | ||
public function createByFilter(Filter $filter): CustomConditionInterface | ||
{ | ||
$attribute = $this->getAttributeByCode($filter->getField()); | ||
|
||
if ($attribute->getBackendTable() === $this->productResource->getEntityTable()) { | ||
return $this->nativeAttributeConditionBuilder; | ||
} | ||
|
||
return $this->eavAttributeConditionBuilder; | ||
} | ||
|
||
/** | ||
* @param string $field | ||
* @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute | ||
* @throws \Magento\Framework\Exception\LocalizedException | ||
*/ | ||
private function getAttributeByCode(string $field): Attribute | ||
{ | ||
return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field); | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
...eria/CollectionProcessor/ConditionProcessor/ConditionBuilder/NativeAttributeCondition.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\ConditionBuilder; | ||
|
||
use Magento\Catalog\Api\Data\ProductInterface; | ||
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionInterface; | ||
use Magento\Framework\Api\Filter; | ||
use Magento\Catalog\Model\ResourceModel\Product\Collection; | ||
|
||
/** | ||
* Based on Magento\Framework\Api\Filter builds condition | ||
* that can be applied to Catalog\Model\ResourceModel\Product\Collection | ||
* to filter products that has specific value for their native attribute | ||
*/ | ||
class NativeAttributeCondition implements CustomConditionInterface | ||
{ | ||
/** | ||
* @var \Magento\Framework\App\ResourceConnection | ||
*/ | ||
private $resourceConnection; | ||
|
||
/** | ||
* @param \Magento\Framework\App\ResourceConnection $resourceConnection | ||
*/ | ||
public function __construct( | ||
\Magento\Framework\App\ResourceConnection $resourceConnection | ||
) { | ||
$this->resourceConnection = $resourceConnection; | ||
} | ||
|
||
/** | ||
* Build condition to filter product collection by product native attribute | ||
* "native" attribute means attribute that is in catalog_product_entity table | ||
* | ||
* @param Filter $filter | ||
* @return string | ||
* @throws \DomainException | ||
*/ | ||
public function build(Filter $filter): string | ||
{ | ||
$conditionType = $this->mapConditionType($filter->getConditionType(), $filter->getField()); | ||
$conditionValue = $this->mapConditionValue($conditionType, $filter->getValue()); | ||
|
||
return $this->resourceConnection | ||
->getConnection() | ||
->prepareSqlCondition( | ||
Collection::MAIN_TABLE_ALIAS . '.' . $filter->getField(), | ||
[ | ||
$conditionType => $conditionValue | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* Map equal and not equal conditions to in and not in | ||
* | ||
* @param string $conditionType | ||
* @param string $field | ||
* @return mixed | ||
*/ | ||
private function mapConditionType(string $conditionType, string $field): string | ||
{ | ||
if (strtolower($field) === ProductInterface::SKU) { | ||
$conditionsMap = [ | ||
'eq' => 'like', | ||
'neq' => 'nlike' | ||
]; | ||
} else { | ||
$conditionsMap = [ | ||
'eq' => 'in', | ||
'neq' => 'nin' | ||
]; | ||
} | ||
|
||
return isset($conditionsMap[$conditionType]) ? $conditionsMap[$conditionType] : $conditionType; | ||
} | ||
|
||
/** | ||
* Wraps value with '%' if condition type is 'like' or 'not like' | ||
* | ||
* @param string $conditionType | ||
* @param string $conditionValue | ||
* @return string | ||
*/ | ||
private function mapConditionValue(string $conditionType, string $conditionValue): string | ||
{ | ||
$conditionsMap = ['like', 'nlike']; | ||
|
||
if (in_array($conditionType, $conditionsMap)) { | ||
$conditionValue = '%' . $conditionValue . '%'; | ||
} | ||
|
||
return $conditionValue; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...alog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/DefaultCondition.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor; | ||
|
||
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionInterface; | ||
use Magento\Framework\Api\Filter; | ||
use Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\ConditionBuilder\Factory; | ||
|
||
/** | ||
* Default condition builder for Catalog\Model\ResourceModel\Product\Collection | ||
*/ | ||
class DefaultCondition implements CustomConditionInterface | ||
{ | ||
/** | ||
* @var Factory | ||
*/ | ||
private $conditionBuilderFactory; | ||
|
||
/** | ||
* @param Factory $conditionBuilderFactory | ||
*/ | ||
public function __construct( | ||
Factory $conditionBuilderFactory | ||
) { | ||
$this->conditionBuilderFactory = $conditionBuilderFactory; | ||
} | ||
|
||
/** | ||
* Builds condition to filter product collection either by EAV or by native attribute | ||
* | ||
* @param Filter $filter | ||
* @return string | ||
*/ | ||
public function build(Filter $filter): string | ||
{ | ||
$filterBuilder = $this->conditionBuilderFactory->createByFilter($filter); | ||
|
||
return $filterBuilder->build($filter); | ||
} | ||
} |
Oops, something went wrong.