6 declare(strict_types=1);
27 private $metadataPool;
32 private $columnValueExpressionFactory;
42 private $connectionName;
47 private $isPriceGlobalFlag;
57 private $tableStrategy;
70 \
Magento\Framework\DB\Sql\ColumnValueExpressionFactory $columnValueExpressionFactory,
72 \
Magento\Framework\Indexer\
Table\StrategyInterface $tableStrategy,
73 $connectionName =
'indexer' 76 $this->metadataPool = $metadataPool;
77 $this->connectionName = $connectionName;
78 $this->columnValueExpressionFactory = $columnValueExpressionFactory;
79 $this->dataHelper = $dataHelper;
80 $this->tableStrategy = $tableStrategy;
95 if (!$this->checkIfCustomOptionsExist($priceTable)) {
99 $connection = $this->getConnection();
102 $coaTable = $this->getCustomOptionAggregateTable();
103 $this->prepareCustomOptionAggregateTable();
105 $copTable = $this->getCustomOptionPriceTable();
106 $this->prepareCustomOptionPriceTable();
108 $select = $this->getSelectForOptionsWithMultipleValues($finalPriceTable);
110 $connection->query(
$query);
112 $select = $this->getSelectForOptionsWithOneValue($finalPriceTable);
114 $connection->query(
$query);
116 $select = $this->getSelectAggregated($coaTable);
118 $connection->query(
$query);
121 $select = $this->getSelectForUpdate($copTable);
122 $query =
$select->crossUpdateFromSelect([
'i' => $finalPriceTable]);
123 $connection->query(
$query);
125 $connection->delete($coaTable);
126 $connection->delete($copTable);
136 $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
138 $select = $this->getConnection()
144 [
'e' => $this->getTable(
'catalog_product_entity')],
145 'e.entity_id = i.entity_id',
148 [
'o' => $this->getTable(
'catalog_product_option')],
149 'o.product_id = e.' . $metadata->getLinkField(),
153 return !empty($this->getConnection()->fetchRow(
$select));
159 private function getConnection()
161 if (
null === $this->connection) {
162 $this->connection = $this->resource->getConnection($this->connectionName);
165 return $this->connection;
175 private function getSelectForOptionsWithMultipleValues(
string $sourceTable):
Select 177 $connection = $this->resource->getConnection($this->connectionName);
178 $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
180 $select = $connection->select()
182 [
'i' => $sourceTable],
183 [
'entity_id',
'customer_group_id',
'website_id']
185 [
'e' => $this->getTable(
'catalog_product_entity')],
186 'e.entity_id = i.entity_id',
189 [
'cwd' => $this->getTable(
'catalog_product_index_website')],
190 'i.website_id = cwd.website_id',
193 [
'o' => $this->getTable(
'catalog_product_option')],
194 'o.product_id = e.' . $metadata->getLinkField(),
197 [
'ot' => $this->getTable(
'catalog_product_option_type_value')],
198 'ot.option_id = o.option_id',
201 [
'otpd' => $this->getTable(
'catalog_product_option_type_price')],
202 'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0',
205 [
'i.entity_id',
'i.customer_group_id',
'i.website_id',
'o.option_id']
208 if ($this->isPriceGlobal()) {
209 $optPriceType =
'otpd.price_type';
210 $optPriceValue =
'otpd.price';
213 [
'otps' => $this->getTable(
'catalog_product_option_type_price')],
214 'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cwd.default_store_id',
218 $optPriceType = $connection->getCheckSql(
219 'otps.option_type_price_id > 0',
223 $optPriceValue = $connection->getCheckSql(
'otps.option_type_price_id > 0',
'otps.price',
'otpd.price');
226 $minPriceRound = $this->columnValueExpressionFactory
228 'expression' =>
"ROUND(i.final_price * ({$optPriceValue} / 100), 4)" 230 $minPriceExpr = $connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
231 $minPriceMin = $this->columnValueExpressionFactory
233 'expression' =>
"MIN({$minPriceExpr})" 235 $minPrice = $connection->getCheckSql(
"MIN(o.is_require) = 1", $minPriceMin,
'0');
237 $tierPriceRound = $this->columnValueExpressionFactory
239 'expression' =>
"ROUND(i.tier_price * ({$optPriceValue} / 100), 4)" 241 $tierPriceExpr = $connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
242 $tierPriceMin = $this->columnValueExpressionFactory
244 'expression' =>
"MIN({$tierPriceExpr})" 246 $tierPriceValue = $connection->getCheckSql(
"MIN(o.is_require) > 0", $tierPriceMin, 0);
247 $tierPrice = $connection->getCheckSql(
"MIN(i.tier_price) IS NOT NULL", $tierPriceValue,
"NULL");
249 $maxPriceRound = $this->columnValueExpressionFactory
251 'expression' =>
"ROUND(i.final_price * ({$optPriceValue} / 100), 4)" 253 $maxPriceExpr = $connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound);
254 $maxPrice = $connection->getCheckSql(
255 "(MIN(o.type)='radio' OR MIN(o.type)='drop_down')",
256 "MAX({$maxPriceExpr})",
257 "SUM({$maxPriceExpr})" 262 'min_price' => $minPrice,
263 'max_price' => $maxPrice,
264 'tier_price' => $tierPrice,
278 private function getSelectForOptionsWithOneValue(
string $sourceTable): Select
280 $connection = $this->resource->getConnection($this->connectionName);
281 $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
283 $select = $connection->select()
285 [
'i' => $sourceTable],
286 [
'entity_id',
'customer_group_id',
'website_id']
288 [
'e' => $this->getTable(
'catalog_product_entity')],
289 'e.entity_id = i.entity_id',
292 [
'cwd' => $this->getTable(
'catalog_product_index_website')],
293 'i.website_id = cwd.website_id',
296 [
'o' => $this->getTable(
'catalog_product_option')],
297 'o.product_id = e.' . $metadata->getLinkField(),
300 [
'opd' => $this->getTable(
'catalog_product_option_price')],
301 'opd.option_id = o.option_id AND opd.store_id = 0',
305 if ($this->isPriceGlobal()) {
306 $optPriceType =
'opd.price_type';
307 $optPriceValue =
'opd.price';
310 [
'ops' => $this->getTable(
'catalog_product_option_price')],
311 'ops.option_id = opd.option_id AND ops.store_id = cwd.default_store_id',
315 $optPriceType = $connection->getCheckSql(
'ops.option_price_id > 0',
'ops.price_type',
'opd.price_type');
316 $optPriceValue = $connection->getCheckSql(
'ops.option_price_id > 0',
'ops.price',
'opd.price');
319 $minPriceRound = $this->columnValueExpressionFactory
321 'expression' =>
"ROUND(i.final_price * ({$optPriceValue} / 100), 4)" 323 $priceExpr = $connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
324 $minPrice = $connection->getCheckSql(
"{$priceExpr} > 0 AND o.is_require = 1", $priceExpr, 0);
326 $maxPrice = $priceExpr;
328 $tierPriceRound = $this->columnValueExpressionFactory
330 'expression' =>
"ROUND(i.tier_price * ({$optPriceValue} / 100), 4)" 332 $tierPriceExpr = $connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
333 $tierPriceValue = $connection->getCheckSql(
"{$tierPriceExpr} > 0 AND o.is_require = 1", $tierPriceExpr, 0);
334 $tierPrice = $connection->getCheckSql(
"i.tier_price IS NOT NULL", $tierPriceValue,
"NULL");
338 'min_price' => $minPrice,
339 'max_price' => $maxPrice,
340 'tier_price' => $tierPrice,
353 private function getSelectAggregated(
string $sourceTable): Select
355 $connection = $this->resource->getConnection($this->connectionName);
357 $select = $connection->select()
364 'min_price' =>
'SUM(min_price)',
365 'max_price' =>
'SUM(max_price)',
366 'tier_price' =>
'SUM(tier_price)',
369 [
'entity_id',
'customer_group_id',
'website_id']
379 private function getSelectForUpdate(
string $sourceTable): Select
381 $connection = $this->resource->getConnection($this->connectionName);
383 $select = $connection->select()->join(
384 [
'io' => $sourceTable],
385 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' .
386 ' AND i.website_id = io.website_id',
391 'min_price' =>
new ColumnValueExpression(
'i.min_price + io.min_price'),
392 'max_price' =>
new ColumnValueExpression(
'i.max_price + io.max_price'),
393 'tier_price' => $connection->getCheckSql(
394 'i.tier_price IS NOT NULL',
395 'i.tier_price + io.tier_price',
408 private function getTable(
string $tableName): string
410 return $this->resource->getTableName(
$tableName, $this->connectionName);
416 private function isPriceGlobal(): bool
418 if ($this->isPriceGlobalFlag ===
null) {
419 $this->isPriceGlobalFlag = $this->dataHelper->isPriceGlobal();
422 return $this->isPriceGlobalFlag;
430 private function getCustomOptionAggregateTable(): string
432 return $this->tableStrategy->getTableName(
'catalog_product_index_price_opt_agr');
440 private function getCustomOptionPriceTable(): string
442 return $this->tableStrategy->getTableName(
'catalog_product_index_price_opt');
450 private function prepareCustomOptionAggregateTable()
452 $this->getConnection()->delete($this->getCustomOptionAggregateTable());
460 private function prepareCustomOptionPriceTable()
462 $this->getConnection()->delete($this->getCustomOptionPriceTable());
__construct(\Magento\Framework\App\ResourceConnection $resource, \Magento\Framework\EntityManager\MetadataPool $metadataPool, \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $columnValueExpressionFactory, \Magento\Catalog\Helper\Data $dataHelper, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, $connectionName='indexer')
modifyPrice(IndexTableStructure $priceTable, array $entityIds=[])