|
1
|
|
|
<?php declare(strict_types=1); |
|
2
|
|
|
|
|
3
|
|
|
namespace Shopware\Elasticsearch\Product; |
|
4
|
|
|
|
|
5
|
|
|
use Doctrine\DBAL\Connection; |
|
6
|
|
|
use OpenSearch\Client; |
|
7
|
|
|
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent; |
|
8
|
|
|
use Shopware\Core\Framework\Log\Package; |
|
9
|
|
|
use Shopware\Core\System\CustomField\CustomFieldDefinition; |
|
10
|
|
|
use Shopware\Core\System\CustomField\CustomFieldTypes; |
|
11
|
|
|
use Shopware\Elasticsearch\Framework\ElasticsearchHelper; |
|
12
|
|
|
use Shopware\Elasticsearch\Framework\ElasticsearchOutdatedIndexDetector; |
|
13
|
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* @internal |
|
17
|
|
|
*/ |
|
18
|
|
|
#[Package('core')] |
|
19
|
|
|
class CustomFieldUpdater implements EventSubscriberInterface |
|
20
|
|
|
{ |
|
21
|
|
|
/** |
|
22
|
|
|
* @internal |
|
23
|
|
|
*/ |
|
24
|
|
|
public function __construct( |
|
25
|
|
|
private readonly ElasticsearchOutdatedIndexDetector $indexDetector, |
|
26
|
|
|
private readonly Client $client, |
|
27
|
|
|
private readonly ElasticsearchHelper $elasticsearchHelper, |
|
28
|
|
|
private readonly Connection $connection |
|
29
|
|
|
) { |
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
|
|
public static function getSubscribedEvents(): array |
|
33
|
|
|
{ |
|
34
|
|
|
return [ |
|
35
|
|
|
EntityWrittenContainerEvent::class => 'onNewCustomFieldCreated', |
|
36
|
|
|
]; |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
public function onNewCustomFieldCreated(EntityWrittenContainerEvent $containerEvent): void |
|
40
|
|
|
{ |
|
41
|
|
|
$event = $containerEvent->getEventByEntityName(CustomFieldDefinition::ENTITY_NAME); |
|
42
|
|
|
|
|
43
|
|
|
if ($event === null) { |
|
44
|
|
|
return; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
if (!$this->elasticsearchHelper->allowIndexing()) { |
|
48
|
|
|
return; |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
$newCreatedFields = []; |
|
52
|
|
|
|
|
53
|
|
|
foreach ($event->getWriteResults() as $writeResult) { |
|
54
|
|
|
$existence = $writeResult->getExistence(); |
|
55
|
|
|
|
|
56
|
|
|
if ($existence && $existence->exists()) { |
|
57
|
|
|
continue; |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
/** @var array<mixed> $esType */ |
|
61
|
|
|
$esType = self::getTypeFromCustomFieldType($writeResult->getProperty('type')); |
|
62
|
|
|
|
|
63
|
|
|
$newCreatedFields[(string) $writeResult->getProperty('name')] = $esType; |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
if (\count($newCreatedFields) === 0) { |
|
67
|
|
|
return; |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
$this->createNewFieldsInIndices($newCreatedFields); |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* @return array<mixed> |
|
75
|
|
|
*/ |
|
76
|
|
|
public static function getTypeFromCustomFieldType(string $type): array |
|
77
|
|
|
{ |
|
78
|
|
|
return match ($type) { |
|
79
|
|
|
CustomFieldTypes::INT => [ |
|
80
|
|
|
'type' => 'long', |
|
81
|
|
|
], |
|
82
|
|
|
CustomFieldTypes::FLOAT => [ |
|
83
|
|
|
'type' => 'double', |
|
84
|
|
|
], |
|
85
|
|
|
CustomFieldTypes::BOOL => [ |
|
86
|
|
|
'type' => 'boolean', |
|
87
|
|
|
], |
|
88
|
|
|
CustomFieldTypes::DATETIME => [ |
|
89
|
|
|
'type' => 'date', |
|
90
|
|
|
'format' => 'yyyy-MM-dd HH:mm:ss.000||strict_date_optional_time||epoch_millis', |
|
91
|
|
|
'ignore_malformed' => true, |
|
92
|
|
|
], |
|
93
|
|
|
CustomFieldTypes::PRICE, CustomFieldTypes::JSON => [ |
|
94
|
|
|
'type' => 'object', |
|
95
|
|
|
'dynamic' => true, |
|
96
|
|
|
], |
|
97
|
|
|
CustomFieldTypes::HTML, CustomFieldTypes::TEXT => [ |
|
98
|
|
|
'type' => 'text', |
|
99
|
|
|
], |
|
100
|
|
|
default => [ |
|
101
|
|
|
'type' => 'keyword', |
|
102
|
|
|
], |
|
103
|
|
|
}; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* @param array<string, array<mixed>> $newCreatedFields |
|
108
|
|
|
*/ |
|
109
|
|
|
private function createNewFieldsInIndices(array $newCreatedFields): void |
|
110
|
|
|
{ |
|
111
|
|
|
$indices = $this->indexDetector->getAllUsedIndices(); |
|
112
|
|
|
|
|
113
|
|
|
$enabledMultilingualIndex = $this->elasticsearchHelper->enabledMultilingualIndex(); |
|
|
|
|
|
|
114
|
|
|
$languageIds = $enabledMultilingualIndex ? $this->connection->fetchFirstColumn('SELECT LOWER(HEX(`id`)) FROM language') : []; |
|
115
|
|
|
|
|
116
|
|
|
foreach ($indices as $indexName) { |
|
117
|
|
|
// Check if index is old language based index |
|
118
|
|
|
$isLanguageBasedIndex = true; |
|
119
|
|
|
|
|
120
|
|
|
$body = [ |
|
121
|
|
|
'properties' => [ |
|
122
|
|
|
'customFields' => [ |
|
123
|
|
|
'properties' => [], |
|
124
|
|
|
], |
|
125
|
|
|
], |
|
126
|
|
|
]; |
|
127
|
|
|
|
|
128
|
|
|
// @deprecated tag:v6.6.0 - Remove this check as old language based indexes will be removed |
|
129
|
|
|
foreach ($languageIds as $languageId) { |
|
130
|
|
|
if (str_contains($indexName, $languageId)) { |
|
131
|
|
|
$isLanguageBasedIndex = true; |
|
132
|
|
|
|
|
133
|
|
|
break; |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
$isLanguageBasedIndex = false; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
if ($isLanguageBasedIndex) { |
|
140
|
|
|
$body['properties']['customFields']['properties'] = $newCreatedFields; |
|
141
|
|
|
} else { |
|
142
|
|
|
foreach ($languageIds as $languageId) { |
|
143
|
|
|
$body['properties']['customFields']['properties'][$languageId] = [ |
|
144
|
|
|
'type' => 'object', |
|
145
|
|
|
'dynamic' => true, |
|
146
|
|
|
'properties' => $newCreatedFields, |
|
147
|
|
|
]; |
|
148
|
|
|
} |
|
149
|
|
|
} |
|
150
|
|
|
|
|
151
|
|
|
// For some reason, we need to include the includes to prevent merge conflicts. |
|
152
|
|
|
// This error can happen for example after updating from version <6.4. |
|
153
|
|
|
$current = $this->client->indices()->get(['index' => $indexName]); |
|
154
|
|
|
$includes = $current[$indexName]['mappings']['_source']['includes'] ?? []; |
|
155
|
|
|
if ($includes !== []) { |
|
156
|
|
|
$body['_source'] = [ |
|
157
|
|
|
'includes' => $includes, |
|
158
|
|
|
]; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
$this->client->indices()->putMapping([ |
|
162
|
|
|
'index' => $indexName, |
|
163
|
|
|
'body' => $body, |
|
164
|
|
|
]); |
|
165
|
|
|
} |
|
166
|
|
|
} |
|
167
|
|
|
} |
|
168
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.