Skip to content

Commit 1f6e546

Browse files
authored
Merge pull request #3296 from magento-helix/MAGETWO-94482
[helix] MAGETWO-94482: [2.3] Fixed procedure of creating mapping for dynamic fields in elasticsearch
2 parents 5393b18 + 09b1563 commit 1f6e546

File tree

66 files changed

+4876
-1062
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4876
-1062
lines changed

app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/BatchDataMapper/CategoryFieldsProvider.php

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Elasticsearch\Elasticsearch5\Model\Adapter\BatchDataMapper;
78

89
use Magento\Elasticsearch\Model\ResourceModel\Index;
910
use Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProviderInterface;
11+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeProvider;
12+
use Magento\Framework\App\ObjectManager;
13+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldName\ResolverInterface;
1014

1115
/**
1216
* Provide data mapping for categories fields
@@ -18,16 +22,35 @@ class CategoryFieldsProvider implements AdditionalFieldsProviderInterface
1822
*/
1923
private $resourceIndex;
2024

25+
/**
26+
* @var AttributeProvider
27+
*/
28+
private $attributeAdapterProvider;
29+
30+
/**
31+
* @var ResolverInterface
32+
*/
33+
private $fieldNameResolver;
34+
2135
/**
2236
* @param Index $resourceIndex
37+
* @param AttributeProvider|null $attributeAdapterProvider
38+
* @param ResolverInterface|null $fieldNameResolver
2339
*/
24-
public function __construct(Index $resourceIndex)
25-
{
40+
public function __construct(
41+
Index $resourceIndex,
42+
AttributeProvider $attributeAdapterProvider = null,
43+
ResolverInterface $fieldNameResolver = null
44+
) {
2645
$this->resourceIndex = $resourceIndex;
46+
$this->attributeAdapterProvider = $attributeAdapterProvider ?: ObjectManager::getInstance()
47+
->get(AttributeProvider::class);
48+
$this->fieldNameResolver = $fieldNameResolver ?: ObjectManager::getInstance()
49+
->get(ResolverInterface::class);
2750
}
2851

2952
/**
30-
* {@inheritdoc}
53+
* @inheritdoc
3154
*/
3255
public function getFields(array $productIds, $storeId)
3356
{
@@ -58,9 +81,19 @@ private function getProductCategoryData($productId, array $categoryIndexData)
5881

5982
if (count($categoryIds)) {
6083
$result = ['category_ids' => $categoryIds];
84+
$positionAttribute = $this->attributeAdapterProvider->getByAttributeCode('position');
85+
$categoryNameAttribute = $this->attributeAdapterProvider->getByAttributeCode('category_name');
6186
foreach ($indexData as $data) {
62-
$result['position_category_' . $data['id']] = $data['position'];
63-
$result['name_category_' . $data['id']] = $data['name'];
87+
$categoryPositionKey = $this->fieldNameResolver->getFieldName(
88+
$positionAttribute,
89+
['categoryId' => $data['id']]
90+
);
91+
$categoryNameKey = $this->fieldNameResolver->getFieldName(
92+
$categoryNameAttribute,
93+
['categoryId' => $data['id']]
94+
);
95+
$result[$categoryPositionKey] = $data['position'];
96+
$result[$categoryNameKey] = $data['name'];
6497
}
6598
}
6699
}

app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/DataMapper/ProductDataMapper.php

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Elasticsearch\Elasticsearch5\Model\Adapter\DataMapper;
78

89
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
@@ -14,8 +15,13 @@
1415
use Magento\Elasticsearch\Model\Adapter\FieldMapperInterface;
1516
use Magento\Elasticsearch\Model\Adapter\DataMapperInterface;
1617
use Magento\Elasticsearch\Model\Adapter\FieldType\Date as DateFieldType;
18+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeProvider;
19+
use Magento\Framework\App\ObjectManager;
20+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldName\ResolverInterface;
1721

1822
/**
23+
* Don't use this product data mapper class.
24+
*
1925
* @deprecated 100.2.0
2026
* @see \Magento\Elasticsearch\Model\Adapter\BatchDataMapperInterface
2127
*/
@@ -78,6 +84,16 @@ class ProductDataMapper implements DataMapperInterface
7884
*/
7985
protected $mediaGalleryRoles;
8086

87+
/**
88+
* @var AttributeProvider
89+
*/
90+
private $attributeAdapterProvider;
91+
92+
/**
93+
* @var ResolverInterface
94+
*/
95+
private $fieldNameResolver;
96+
8197
/**
8298
* Construction for DocumentDataMapper
8399
*
@@ -87,21 +103,29 @@ class ProductDataMapper implements DataMapperInterface
87103
* @param FieldMapperInterface $fieldMapper
88104
* @param StoreManagerInterface $storeManager
89105
* @param DateFieldType $dateFieldType
106+
* @param AttributeProvider|null $attributeAdapterProvider
107+
* @param ResolverInterface|null $fieldNameResolver
90108
*/
91109
public function __construct(
92110
Builder $builder,
93111
AttributeContainer $attributeContainer,
94112
Index $resourceIndex,
95113
FieldMapperInterface $fieldMapper,
96114
StoreManagerInterface $storeManager,
97-
DateFieldType $dateFieldType
115+
DateFieldType $dateFieldType,
116+
AttributeProvider $attributeAdapterProvider = null,
117+
ResolverInterface $fieldNameResolver = null
98118
) {
99119
$this->builder = $builder;
100120
$this->attributeContainer = $attributeContainer;
101121
$this->resourceIndex = $resourceIndex;
102122
$this->fieldMapper = $fieldMapper;
103123
$this->storeManager = $storeManager;
104124
$this->dateFieldType = $dateFieldType;
125+
$this->attributeAdapterProvider = $attributeAdapterProvider ?: ObjectManager::getInstance()
126+
->get(AttributeProvider::class);
127+
$this->fieldNameResolver = $fieldNameResolver ?: ObjectManager::getInstance()
128+
->get(ResolverInterface::class);
105129

106130
$this->mediaGalleryRoles = [
107131
self::MEDIA_ROLE_IMAGE,
@@ -203,6 +227,8 @@ protected function processAdvancedAttributes($productId, array $productIndexData
203227
}
204228

205229
/**
230+
* Check value.
231+
*
206232
* @param mixed $value
207233
* @param Attribute $attribute
208234
* @param string $storeId
@@ -232,14 +258,14 @@ protected function getProductTierPriceData($data)
232258
if (!empty($data)) {
233259
$i = 0;
234260
foreach ($data as $tierPrice) {
235-
$result['tier_price_id_'.$i] = $tierPrice['price_id'];
236-
$result['tier_website_id_'.$i] = $tierPrice['website_id'];
237-
$result['tier_all_groups_'.$i] = $tierPrice['all_groups'];
238-
$result['tier_cust_group_'.$i] = $tierPrice['cust_group'] == GroupInterface::CUST_GROUP_ALL
261+
$result['tier_price_id_' . $i] = $tierPrice['price_id'];
262+
$result['tier_website_id_' . $i] = $tierPrice['website_id'];
263+
$result['tier_all_groups_' . $i] = $tierPrice['all_groups'];
264+
$result['tier_cust_group_' . $i] = $tierPrice['cust_group'] == GroupInterface::CUST_GROUP_ALL
239265
? '' : $tierPrice['cust_group'];
240-
$result['tier_price_qty_'.$i] = $tierPrice['price_qty'];
241-
$result['tier_website_price_'.$i] = $tierPrice['website_price'];
242-
$result['tier_price_'.$i] = $tierPrice['price'];
266+
$result['tier_price_qty_' . $i] = $tierPrice['price_qty'];
267+
$result['tier_website_price_' . $i] = $tierPrice['website_price'];
268+
$result['tier_price_' . $i] = $tierPrice['price'];
243269
$i++;
244270
}
245271
}
@@ -293,6 +319,8 @@ protected function getProductMediaGalleryData($media, $roles)
293319
}
294320

295321
/**
322+
* Get media role image.
323+
*
296324
* @param string $file
297325
* @param array $roles
298326
* @return string
@@ -303,6 +331,8 @@ protected function getMediaRoleImage($file, $roles)
303331
}
304332

305333
/**
334+
* Get media role small image.
335+
*
306336
* @param string $file
307337
* @param array $roles
308338
* @return string
@@ -313,6 +343,8 @@ protected function getMediaRoleSmallImage($file, $roles)
313343
}
314344

315345
/**
346+
* Get media role thumbnail.
347+
*
316348
* @param string $file
317349
* @param array $roles
318350
* @return string
@@ -323,6 +355,8 @@ protected function getMediaRoleThumbnail($file, $roles)
323355
}
324356

325357
/**
358+
* Get media role swatch image.
359+
*
326360
* @param string $file
327361
* @param array $roles
328362
* @return string
@@ -364,9 +398,11 @@ protected function getProductPriceData($productId, $storeId, array $priceIndexDa
364398
$result = [];
365399
if (array_key_exists($productId, $priceIndexData)) {
366400
$productPriceIndexData = $priceIndexData[$productId];
367-
$websiteId = $this->storeManager->getStore($storeId)->getWebsiteId();
368401
foreach ($productPriceIndexData as $customerGroupId => $price) {
369-
$fieldName = 'price_' . $customerGroupId . '_' . $websiteId;
402+
$fieldName = $this->fieldMapper->getFieldName(
403+
'price',
404+
['customerGroupId' => $customerGroupId, 'websiteId' => $storeId]
405+
);
370406
$result[$fieldName] = sprintf('%F', $price);
371407
}
372408
}
@@ -393,13 +429,23 @@ protected function getProductCategoryData($productId, array $categoryIndexData)
393429
if (array_key_exists($productId, $categoryIndexData)) {
394430
$indexData = $categoryIndexData[$productId];
395431
foreach ($indexData as $categoryData) {
396-
$categoryIds[] = (int) $categoryData['id'];
432+
$categoryIds[] = (int)$categoryData['id'];
397433
}
398434
if (count($categoryIds)) {
399435
$result = ['category_ids' => implode(' ', $categoryIds)];
436+
$positionAttribute = $this->attributeAdapterProvider->getByAttributeCode('position');
437+
$categoryNameAttribute = $this->attributeAdapterProvider->getByAttributeCode('category_name');
400438
foreach ($indexData as $data) {
401-
$result['position_category_' . $data['id']] = $data['position'];
402-
$result['name_category_' . $data['id']] = $data['name'];
439+
$categoryPositionKey = $this->fieldNameResolver->getFieldName(
440+
$positionAttribute,
441+
['categoryId' => $data['id']]
442+
);
443+
$categoryNameKey = $this->fieldNameResolver->getFieldName(
444+
$categoryNameAttribute,
445+
['categoryId' => $data['id']]
446+
);
447+
$result[$categoryPositionKey] = $data['position'];
448+
$result[$categoryNameKey] = $data['name'];
403449
}
404450
}
405451
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
namespace Magento\Elasticsearch\Elasticsearch5\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex;
9+
10+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex\ConverterInterface;
11+
12+
/**
13+
* Field type converter from internal index type to elastic service.
14+
*/
15+
class Converter implements ConverterInterface
16+
{
17+
/**
18+
* Text flags for Elasticsearch index value
19+
*/
20+
private const ES_NO_INDEX = false;
21+
22+
/**
23+
* Mapping between internal data types and elastic service.
24+
*
25+
* @var array
26+
*/
27+
private $mapping = [
28+
'no_index' => self::ES_NO_INDEX,
29+
];
30+
31+
/**
32+
* Get service field index type for elasticsearch 5.
33+
*
34+
* @param string $internalType
35+
* @return string|boolean
36+
* @throws \DomainException
37+
*/
38+
public function convert(string $internalType)
39+
{
40+
if (!isset($this->mapping[$internalType])) {
41+
throw new \DomainException(sprintf('Unsupported internal field index type: %s', $internalType));
42+
}
43+
return $this->mapping[$internalType];
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
namespace Magento\Elasticsearch\Elasticsearch5\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex;
9+
10+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeAdapter;
11+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex\ResolverInterface;
12+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex\ConverterInterface;
13+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\ConverterInterface
14+
as FieldTypeConverterInterface;
15+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\ResolverInterface
16+
as FieldTypeResolver;
17+
18+
/**
19+
* Field index resolver that provides index type for the attribute in mapping.
20+
* For example, we need to set ‘no’/false in the case when attribute must be present in index data,
21+
* but stay as not indexable.
22+
*/
23+
class IndexResolver implements ResolverInterface
24+
{
25+
/**
26+
* @var ConverterInterface
27+
*/
28+
private $converter;
29+
30+
/**
31+
* @var FieldTypeConverterInterface
32+
*/
33+
private $fieldTypeConverter;
34+
35+
/**
36+
* @var FieldTypeResolver
37+
*/
38+
private $fieldTypeResolver;
39+
40+
/**
41+
* @param ConverterInterface $converter
42+
* @param FieldTypeConverterInterface $fieldTypeConverter
43+
* @param FieldTypeResolver $fieldTypeResolver
44+
*/
45+
public function __construct(
46+
ConverterInterface $converter,
47+
FieldTypeConverterInterface $fieldTypeConverter,
48+
FieldTypeResolver $fieldTypeResolver
49+
) {
50+
$this->converter = $converter;
51+
$this->fieldTypeConverter = $fieldTypeConverter;
52+
$this->fieldTypeResolver = $fieldTypeResolver;
53+
}
54+
55+
/**
56+
* @inheritdoc
57+
*/
58+
public function getFieldIndex(AttributeAdapter $attribute)
59+
{
60+
$index = null;
61+
if (!$attribute->isSearchable()
62+
&& !$attribute->isAlwaysIndexable()
63+
&& ($this->isStringServiceFieldType($attribute) || $attribute->isComplexType())
64+
&& !(($attribute->isIntegerType() || $attribute->isBooleanType())
65+
&& !$attribute->isUserDefined())
66+
&& !$attribute->isFloatType()
67+
) {
68+
$index = $this->converter->convert(ConverterInterface::INTERNAL_NO_INDEX_VALUE);
69+
}
70+
71+
return $index;
72+
}
73+
74+
/**
75+
* Check if service field type for field set as 'string'
76+
*
77+
* @param AttributeAdapter $attribute
78+
* @return bool
79+
*/
80+
private function isStringServiceFieldType(AttributeAdapter $attribute): bool
81+
{
82+
$serviceFieldType = $this->fieldTypeResolver->getFieldType($attribute);
83+
$stringTypeKey = $this->fieldTypeConverter->convert(FieldTypeConverterInterface::INTERNAL_DATA_TYPE_STRING);
84+
85+
return $serviceFieldType === $stringTypeKey;
86+
}
87+
}

0 commit comments

Comments
 (0)