Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
UpgradeWebsiteAttributes.php
Go to the documentation of this file.
1 <?php
8 
17 
25 {
29  const ATTRIBUTE_WEBSITE = 2;
31  const MASK_ATTRIBUTE_VALUE = '%d_%d_%d';
32 
36  private $tableMetaDataClass = [
37  'catalog_category_entity_datetime' => CategoryInterface::class,
38  'catalog_category_entity_decimal' => CategoryInterface::class,
39  'catalog_category_entity_int' => CategoryInterface::class,
40  'catalog_category_entity_text' => CategoryInterface::class,
41  'catalog_category_entity_varchar' => CategoryInterface::class,
42 
43  'catalog_product_entity_datetime' => ProductInterface::class,
44  'catalog_product_entity_decimal' => ProductInterface::class,
45  'catalog_product_entity_int' => ProductInterface::class,
46  'catalog_product_entity_text' => ProductInterface::class,
47  'catalog_product_entity_varchar' => ProductInterface::class,
48  ];
49 
62  private $groupedStoreViews = [];
63 
67  private $processedAttributeValues = [];
68 
72  private $batchQueryGenerator;
73 
77  private $metaDataPool;
78 
82  private $linkFields = [];
83 
87  private $moduleDataSetup;
88 
95  public function __construct(
96  Generator $batchQueryGenerator,
97  MetadataPool $metadataPool,
98  ModuleDataSetupInterface $moduleDataSetup
99  ) {
100  $this->batchQueryGenerator = $batchQueryGenerator;
101  $this->metaDataPool = $metadataPool;
102  $this->moduleDataSetup = $moduleDataSetup;
103  }
104 
108  public function apply()
109  {
110  foreach (array_keys($this->tableMetaDataClass) as $tableName) {
111  $this->upgradeTable($tableName);
112  }
113  }
114 
119  private function upgradeTable($tableName)
120  {
121  foreach ($this->fetchAttributeValues($tableName) as $attributeValueItems) {
122  $this->processAttributeValues($attributeValueItems, $tableName);
123  }
124  }
125 
132  private function processAttributeValues(array $attributeValueItems, $tableName)
133  {
134  $this->resetProcessedAttributeValues();
135 
136  foreach ($attributeValueItems as $attributeValueItem) {
137  if ($this->isProcessedAttributeValue($attributeValueItem, $tableName)) {
138  continue;
139  }
140 
141  $insertions = $this->generateAttributeValueInsertions($attributeValueItem, $tableName);
142  if (!empty($insertions)) {
143  $this->executeInsertions($insertions, $tableName);
144  }
145 
146  $this->markAttributeValueProcessed($attributeValueItem, $tableName);
147  }
148  }
149 
157  private function fetchAttributeValues($tableName)
158  {
159  //filter store groups which have more than 1 store
160  $multipleStoresInWebsite = array_values(
161  array_reduce(
162  array_filter($this->getGroupedStoreViews(), function ($storeViews) {
163  return is_array($storeViews) && count($storeViews) > 1;
164  }),
165  'array_merge',
166  []
167  )
168  );
169 
170  if (count($multipleStoresInWebsite) < 1) {
171  return [];
172  }
173 
174  $connection = $this->moduleDataSetup->getConnection();
175  $batchSelectIterator = $this->batchQueryGenerator->generate(
176  'value_id',
178  ->select()
179  ->from(
180  ['cpei' => $this->moduleDataSetup->getTable($tableName)],
181  '*'
182  )
183  ->join(
184  [
185  'cea' => $this->moduleDataSetup->getTable('catalog_eav_attribute'),
186  ],
187  'cpei.attribute_id = cea.attribute_id',
188  ''
189  )
190  ->join(
191  [
192  'st' => $this->moduleDataSetup->getTable('store'),
193  ],
194  'st.store_id = cpei.store_id',
195  'st.website_id'
196  )
197  ->where(
198  'cea.is_global = ?',
199  self::ATTRIBUTE_WEBSITE
200  )
201  ->where(
202  'cpei.store_id IN (?)',
203  $multipleStoresInWebsite
204  ),
205  1000
206  );
207 
208  foreach ($batchSelectIterator as $select) {
209  yield $connection->fetchAll($select);
210  }
211  }
212 
216  private function getGroupedStoreViews()
217  {
218  if (!empty($this->groupedStoreViews)) {
219  return $this->groupedStoreViews;
220  }
221 
222  $connection = $this->moduleDataSetup->getConnection();
224  ->select()
225  ->from(
226  $this->moduleDataSetup->getTable('store'),
227  '*'
228  );
229 
230  $storeViews = $connection->fetchAll($query);
231 
232  $this->groupedStoreViews = [];
233 
234  foreach ($storeViews as $storeView) {
235  if ($storeView['store_id'] != 0) {
236  $this->groupedStoreViews[$storeView['website_id']][] = $storeView['store_id'];
237  }
238  }
239 
240  return $this->groupedStoreViews;
241  }
242 
248  private function isProcessedAttributeValue(array $attributeValue, $tableName)
249  {
250  return in_array(
251  $this->getAttributeValueKey(
252  $attributeValue[$this->getTableLinkField($tableName)],
253  $attributeValue['attribute_id'],
254  $attributeValue['website_id']
255  ),
256  $this->processedAttributeValues
257  );
258  }
259 
264  private function resetProcessedAttributeValues()
265  {
266  $this->processedAttributeValues = [];
267  }
268 
274  private function markAttributeValueProcessed(array $attributeValue, $tableName)
275  {
276  $this->processedAttributeValues[] = $this->getAttributeValueKey(
277  $attributeValue[$this->getTableLinkField($tableName)],
278  $attributeValue['attribute_id'],
279  $attributeValue['website_id']
280  );
281  }
282 
289  private function getAttributeValueKey($entityId, $attributeId, $websiteId)
290  {
291  return sprintf(
292  self::MASK_ATTRIBUTE_VALUE,
293  $entityId,
294  $attributeId,
295  $websiteId
296  );
297  }
298 
304  private function generateAttributeValueInsertions(
305  array $attributeValue,
306  $tableName
307  ) {
308  $groupedStoreViews = $this->getGroupedStoreViews();
309  if (empty($groupedStoreViews[$attributeValue['website_id']])) {
310  return null;
311  }
312 
313  $currentStoreViewIds = $groupedStoreViews[$attributeValue['website_id']];
314  $insertions = [];
315 
316  foreach ($currentStoreViewIds as $index => $storeViewId) {
317  $insertions[] = [
318  ':attribute_id' . $index => $attributeValue['attribute_id'],
319  ':store_id' . $index => $storeViewId,
320  ':entity_id' . $index => $attributeValue[$this->getTableLinkField($tableName)],
321  ':value' . $index => $attributeValue['value'],
322  ];
323  }
324 
325  return $insertions;
326  }
327 
333  private function executeInsertions(array $insertions, $tableName)
334  {
335  $rawQuery = sprintf(
336  'INSERT INTO
337  %s(attribute_id, store_id, %s, `value`)
338  VALUES
339  %s
340  ON duplicate KEY UPDATE `value` = VALUES(`value`)',
341  $this->moduleDataSetup->getTable($tableName),
342  $this->getTableLinkField($tableName),
343  $this->prepareInsertValuesStatement($insertions)
344  );
345 
346  $this->moduleDataSetup->getConnection()->query($rawQuery, $this->getPlaceholderValues($insertions));
347  }
348 
355  private function getPlaceholderValues(array $insertions)
356  {
357  $placeholderValues = [];
358  foreach ($insertions as $insertion) {
359  $placeholderValues = array_merge(
360  $placeholderValues,
361  $insertion
362  );
363  }
364 
365  return $placeholderValues;
366  }
367 
374  private function prepareInsertValuesStatement(array $insertions)
375  {
376  $statement = '';
377 
378  foreach ($insertions as $insertion) {
379  $statement .= sprintf('(%s),', implode(',', array_keys($insertion)));
380  }
381 
382  return rtrim($statement, ',');
383  }
384 
390  private function getTableLinkField($tableName)
391  {
392  if (!isset($this->tableMetaDataClass[$tableName])) {
393  throw new LocalizedException(
394  sprintf(
395  'Specified table: %s is not defined in tables list',
396  $tableName
397  )
398  );
399  }
400 
401  if (!isset($this->linkFields[$tableName])) {
402  $this->linkFields[$tableName] = $this->metaDataPool
403  ->getMetadata($this->tableMetaDataClass[$tableName])
404  ->getLinkField();
405  }
406 
407  return $this->linkFields[$tableName];
408  }
409 
413  public static function getDependencies()
414  {
415  return [
416  UpgradeWidgetData::class,
417  ];
418  }
419 
423  public static function getVersion()
424  {
425  return '2.2.2';
426  }
427 
431  public function getAliases()
432  {
433  return [];
434  }
435 }
$tableName
Definition: trigger.php:13
__construct(Generator $batchQueryGenerator, MetadataPool $metadataPool, ModuleDataSetupInterface $moduleDataSetup)
$connection
Definition: bulk.php:13
$index
Definition: list.phtml:44