Skip to content

Commit 87ff8d5

Browse files
committed
Merge remote-tracking branch 'origin/MC-19916' into 2.3-develop-pr34
2 parents d4b9b82 + 4032be0 commit 87ff8d5

File tree

4 files changed

+228
-2
lines changed

4 files changed

+228
-2
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
99
use Magento\Catalog\Api\Data\ProductInterface;
1010
use Magento\Catalog\Api\Data\ProductAttributeInterface;
11+
use Magento\Framework\DB\Select;
12+
use Magento\Framework\DB\Sql\UnionExpression;
1113

1214
/**
1315
* Catalog Product Eav Select and Multiply Select Attributes Indexer resource model
@@ -199,13 +201,52 @@ protected function _prepareSelectIndex($entityIds = null, $attributeId = null)
199201
'dd.attribute_id',
200202
's.store_id',
201203
'value' => new \Zend_Db_Expr('COALESCE(ds.value, dd.value)'),
202-
'cpe.entity_id',
204+
'cpe.entity_id AS source_id',
203205
]
204206
);
205207

206208
if ($entityIds !== null) {
207209
$ids = implode(',', array_map('intval', $entityIds));
210+
$selectWithoutDefaultStore = $connection->select()->from(
211+
['wd' => $this->getTable('catalog_product_entity_int')],
212+
[
213+
'cpe.entity_id',
214+
'attribute_id',
215+
'store_id',
216+
'value',
217+
'cpe.entity_id',
218+
]
219+
)->joinLeft(
220+
['cpe' => $this->getTable('catalog_product_entity')],
221+
"cpe.{$productIdField} = wd.{$productIdField}",
222+
[]
223+
)->joinLeft(
224+
['d2d' => $this->getTable('catalog_product_entity_int')],
225+
sprintf(
226+
"d2d.store_id = 0 AND d2d.{$productIdField} = wd.{$productIdField} AND d2d.attribute_id = %s",
227+
$this->_eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'status')->getId()
228+
),
229+
[]
230+
)->joinLeft(
231+
['d2s' => $this->getTable('catalog_product_entity_int')],
232+
"d2s.store_id != 0 AND d2s.attribute_id = d2d.attribute_id AND " .
233+
"d2s.{$productIdField} = d2d.{$productIdField}",
234+
[]
235+
)
236+
->where((new \Zend_Db_Expr('COALESCE(d2s.value, d2d.value)')) . ' = ' . ProductStatus::STATUS_ENABLED)
237+
->where("wd.attribute_id IN({$attrIdsFlat})")
238+
->where('wd.value IS NOT NULL')
239+
->where('wd.store_id != 0')
240+
->where("cpe.entity_id IN({$ids})");
208241
$select->where("cpe.entity_id IN({$ids})");
242+
$selects = new UnionExpression(
243+
[$select, $selectWithoutDefaultStore],
244+
Select::SQL_UNION,
245+
'( %s )'
246+
);
247+
248+
$select = $connection->select();
249+
$select->from(['u' => $selects]);
209250
}
210251

211252
/**
@@ -342,7 +383,7 @@ private function getMultiSelectAttributeWithSourceModels($attrIds)
342383
ProductAttributeInterface::ENTITY_TYPE_CODE,
343384
$criteria
344385
)->getItems();
345-
386+
346387
$options = [];
347388
foreach ($attributes as $attribute) {
348389
$sourceModelOptions = $attribute->getOptions();

dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77

88
use Magento\Catalog\Api\ProductRepositoryInterface;
99
use Magento\Catalog\Model\Product\Attribute\Source\Status;
10+
use Magento\Eav\Api\Data\AttributeOptionInterface;
1011
use Magento\TestFramework\Helper\Bootstrap;
1112
use Magento\Catalog\_files\MultiselectSourceMock;
13+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
14+
use Magento\Store\Model\StoreManagerInterface;
15+
use Magento\Store\Api\Data\StoreInterface;
1216

1317
/**
1418
* Class SourceTest
1519
* @magentoAppIsolation enabled
20+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1621
*/
1722
class SourceTest extends \PHPUnit\Framework\TestCase
1823
{
@@ -159,6 +164,42 @@ public function testReindexMultiselectAttribute()
159164
$this->assertCount(3, $result);
160165
}
161166

167+
/**
168+
* Test for indexing product attribute without "all store view" value
169+
*
170+
* @magentoDataFixture Magento/Catalog/_files/products_with_dropdown_attribute_without_all_store_view.php
171+
* @magentoDbIsolation disabled
172+
*/
173+
public function testReindexSelectAttributeWithoutDefault()
174+
{
175+
$objectManager = Bootstrap::getObjectManager();
176+
/** @var StoreInterface $store */
177+
$store = $objectManager->get(StoreManagerInterface::class)
178+
->getStore();
179+
/** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute **/
180+
$attribute = $objectManager->get(\Magento\Eav\Model\Config::class)
181+
->getAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'dropdown_without_default');
182+
/** @var AttributeOptionInterface $option */
183+
$option = $attribute->getOptions()[1];
184+
/** @var ProductRepositoryInterface $productRepository */
185+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
186+
$product = $productRepository->get('test_attribute_dropdown_without_default', false, 1);
187+
$expected = [
188+
'entity_id' => $product->getId(),
189+
'attribute_id' => $attribute->getId(),
190+
'store_id' => $store->getId(),
191+
'value' => $option->getValue(),
192+
'source_id' => $product->getId(),
193+
];
194+
$connection = $this->productResource->getConnection();
195+
$select = $connection->select()->from($this->productResource->getTable('catalog_product_index_eav'))
196+
->where('entity_id = ?', $product->getId())
197+
->where('attribute_id = ?', $attribute->getId());
198+
199+
$result = $connection->fetchRow($select);
200+
$this->assertEquals($expected, $result);
201+
}
202+
162203
/**
163204
* @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute_with_source_model.php
164205
* @magentoDbIsolation disabled
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
9+
use Magento\Catalog\Api\ProductRepositoryInterface;
10+
use Magento\TestFramework\Helper\Bootstrap;
11+
use Magento\Eav\Api\AttributeRepositoryInterface;
12+
use Magento\Eav\Model\Config as EavConfig;
13+
use Magento\Catalog\Setup\CategorySetup;
14+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
15+
use Magento\Catalog\Api\Data\ProductInterface;
16+
use Magento\Catalog\Model\Product\Type as ProductType;
17+
use Magento\Catalog\Model\Product\Visibility;
18+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
19+
use Magento\Eav\Api\AttributeOptionManagementInterface;
20+
use Magento\Eav\Api\Data\AttributeOptionInterface;
21+
use Magento\Store\Model\StoreManagerInterface;
22+
use Magento\Store\Api\Data\StoreInterface;
23+
24+
$objectManager = Bootstrap::getObjectManager();
25+
$storeManager = $objectManager->get(StoreManagerInterface::class);
26+
/** @var StoreInterface $store */
27+
$store = $storeManager->getStore();
28+
$eavConfig = $objectManager->get(EavConfig::class);
29+
$eavConfig->clear();
30+
$attribute = $eavConfig->getAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'dropdown_without_default');
31+
/** @var CategorySetup $installer */
32+
$installer = $objectManager->get(CategorySetup::class);
33+
$attributeSetId = $installer->getAttributeSetId(ProductAttributeInterface::ENTITY_TYPE_CODE, 'Default');
34+
35+
/** @var ProductInterface $product */
36+
$product = $objectManager->get(ProductInterface::class);
37+
$product->setTypeId(ProductType::TYPE_SIMPLE)
38+
->setAttributeSetId($attributeSetId)
39+
->setName('Simple Product1')
40+
->setSku('test_attribute_dropdown_without_default')
41+
->setPrice(10)
42+
->setVisibility(Visibility::VISIBILITY_BOTH)
43+
->setStatus(Status::STATUS_ENABLED);
44+
/** @var ProductRepositoryInterface $productRepository */
45+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
46+
$product = $productRepository->save($product);
47+
48+
if (!$attribute->getId()) {
49+
/** @var $attribute */
50+
$attribute = $objectManager->get(EavAttribute::class);
51+
/** @var AttributeRepositoryInterface $attributeRepository */
52+
$attributeRepository = $objectManager->get(AttributeRepositoryInterface::class);
53+
$attribute->setData(
54+
[
55+
'attribute_code' => 'dropdown_without_default',
56+
'entity_type_id' => $installer->getEntityTypeId(ProductAttributeInterface::ENTITY_TYPE_CODE),
57+
'is_global' => 0,
58+
'is_user_defined' => 1,
59+
'frontend_input' => 'select',
60+
'is_unique' => 0,
61+
'is_required' => 0,
62+
'is_searchable' => 1,
63+
'is_visible_in_advanced_search' => 1,
64+
'is_comparable' => 1,
65+
'is_filterable' => 1,
66+
'is_filterable_in_search' => 1,
67+
'is_used_for_promo_rules' => 0,
68+
'is_html_allowed_on_front' => 1,
69+
'is_visible_on_front' => 1,
70+
'used_in_product_listing' => 1,
71+
'used_for_sort_by' => 1,
72+
'frontend_label' => ['Test Configurable'],
73+
'backend_type' => 'int',
74+
'option' => [
75+
'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']],
76+
'order' => ['option_0' => 1, 'option_1' => 2],
77+
],
78+
]
79+
);
80+
$attributeRepository->save($attribute);
81+
/* Assign attribute to attribute set */
82+
$installer->addAttributeToGroup(
83+
ProductAttributeInterface::ENTITY_TYPE_CODE,
84+
'Default',
85+
'General',
86+
$attribute->getId()
87+
);
88+
}
89+
/** @var AttributeOptionManagementInterface $options */
90+
$attributeOption = $objectManager->get(AttributeOptionManagementInterface::class);
91+
/* Getting the first nonempty option */
92+
/** @var AttributeOptionInterface $option */
93+
$option = $attributeOption->getItems($attribute->getEntityTypeId(), $attribute->getAttributeCode())[1];
94+
$product->setStoreId($store->getId())
95+
->setData('dropdown_without_default', $option->getValue());
96+
$productRepository->save($product);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Framework\Exception\NoSuchEntityException;
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
use Magento\Eav\Api\AttributeRepositoryInterface;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Eav\Model\Config as EavConfig;
13+
use Magento\Eav\Api\Data\AttributeInterface;
14+
use Magento\Catalog\Api\Data\ProductInterface;
15+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
16+
use Magento\Catalog\Model\Indexer\Product\Eav as ProductEav;
17+
use Magento\Framework\Registry;
18+
19+
$objectManager = Bootstrap::getObjectManager();
20+
/** @var \Magento\Framework\Registry $registry */
21+
$registry = $objectManager->get(Registry::class);
22+
$registry->unregister('isSecureArea');
23+
$registry->register('isSecureArea', true);
24+
25+
$eavConfig = $objectManager->get(EavConfig::class);
26+
$eavConfig->clear();
27+
/** @var AttributeRepositoryInterface $attributeRepository */
28+
$attributeRepository = $objectManager->get(AttributeRepositoryInterface::class);
29+
/** @var ProductRepositoryInterface $productRepository */
30+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
31+
try {
32+
/** @var AttributeInterface $attribute */
33+
$attribute = $attributeRepository->get(ProductAttributeInterface::ENTITY_TYPE_CODE, 'dropdown_without_default');
34+
$attributeRepository->delete($attribute);
35+
} catch (NoSuchEntityException $e) {
36+
//Attribute already deleted
37+
}
38+
try {
39+
/** @var ProductInterface $product */
40+
$product = $productRepository->get('test_attribute_dropdown_without_default');
41+
$productRepository->delete($product);
42+
} catch (NoSuchEntityException $e) {
43+
//Product already deleted
44+
}
45+
$objectManager->get(ProductEav::class)->executeRow($product->getId());
46+
47+
$registry->unregister('isSecureArea');
48+
$registry->register('isSecureArea', false);

0 commit comments

Comments
 (0)