|
9 | 9 | use Magento\CatalogImportExport\Model\Export\RowCustomizerInterface;
|
10 | 10 | use Magento\CatalogImportExport\Model\Import\Product as ImportProductModel;
|
11 | 11 | use Magento\Bundle\Model\ResourceModel\Selection\Collection as SelectionCollection;
|
12 |
| -use Magento\ImportExport\Controller\Adminhtml\Import; |
13 | 12 | use Magento\ImportExport\Model\Import as ImportModel;
|
14 |
| -use \Magento\Catalog\Model\Product\Type\AbstractType; |
| 13 | +use Magento\Catalog\Model\Product\Type\AbstractType; |
| 14 | +use Magento\Store\Model\StoreManagerInterface; |
15 | 15 |
|
16 | 16 | /**
|
17 | 17 | * Class RowCustomizer
|
@@ -105,6 +105,34 @@ class RowCustomizer implements RowCustomizerInterface
|
105 | 105 | AbstractType::SHIPMENT_SEPARATELY => 'separately',
|
106 | 106 | ];
|
107 | 107 |
|
| 108 | + /** |
| 109 | + * @var \Magento\Bundle\Model\ResourceModel\Option\Collection[] |
| 110 | + */ |
| 111 | + private $optionCollections = []; |
| 112 | + |
| 113 | + /** |
| 114 | + * @var array |
| 115 | + */ |
| 116 | + private $storeIdToCode = []; |
| 117 | + |
| 118 | + /** |
| 119 | + * @var string |
| 120 | + */ |
| 121 | + private $optionCollectionCacheKey = '_cache_instance_options_collection'; |
| 122 | + |
| 123 | + /** |
| 124 | + * @var StoreManagerInterface |
| 125 | + */ |
| 126 | + private $storeManager; |
| 127 | + |
| 128 | + /** |
| 129 | + * @param StoreManagerInterface $storeManager |
| 130 | + */ |
| 131 | + public function __construct(StoreManagerInterface $storeManager) |
| 132 | + { |
| 133 | + $this->storeManager = $storeManager; |
| 134 | + } |
| 135 | + |
108 | 136 | /**
|
109 | 137 | * Retrieve list of bundle specific columns
|
110 | 138 | * @return array
|
@@ -205,17 +233,15 @@ protected function populateBundleData($collection)
|
205 | 233 | * @param \Magento\Catalog\Model\Product $product
|
206 | 234 | * @return string
|
207 | 235 | */
|
208 |
| - protected function getFormattedBundleOptionValues($product) |
| 236 | + protected function getFormattedBundleOptionValues(\Magento\Catalog\Model\Product $product): string |
209 | 237 | {
|
210 |
| - /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */ |
211 |
| - $optionsCollection = $product->getTypeInstance() |
212 |
| - ->getOptionsCollection($product) |
213 |
| - ->setOrder('position', Collection::SORT_ORDER_ASC); |
214 |
| - |
| 238 | + $optionCollections = $this->getProductOptionCollection($product); |
215 | 239 | $bundleData = '';
|
216 |
| - foreach ($optionsCollection as $option) { |
| 240 | + $optionTitles = $this->getBundleOptionTitles($product); |
| 241 | + foreach ($optionCollections->getItems() as $option) { |
| 242 | + $optionValues = $this->getFormattedOptionValues($option, $optionTitles); |
217 | 243 | $bundleData .= $this->getFormattedBundleSelections(
|
218 |
| - $this->getFormattedOptionValues($option), |
| 244 | + $optionValues, |
219 | 245 | $product->getTypeInstance()
|
220 | 246 | ->getSelectionsCollection([$option->getId()], $product)
|
221 | 247 | ->setOrder('position', Collection::SORT_ORDER_ASC)
|
@@ -267,16 +293,25 @@ function ($value, $key) {
|
267 | 293 | * Retrieve option value of bundle product
|
268 | 294 | *
|
269 | 295 | * @param \Magento\Bundle\Model\Option $option
|
| 296 | + * @param string[] $optionTitles |
270 | 297 | * @return string
|
271 | 298 | */
|
272 |
| - protected function getFormattedOptionValues($option) |
273 |
| - { |
274 |
| - return 'name' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR |
275 |
| - . $option->getTitle() . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR |
276 |
| - . 'type' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR |
277 |
| - . $option->getType() . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR |
278 |
| - . 'required' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR |
279 |
| - . $option->getRequired(); |
| 299 | + protected function getFormattedOptionValues( |
| 300 | + \Magento\Bundle\Model\Option $option, |
| 301 | + array $optionTitles = [] |
| 302 | + ): string { |
| 303 | + $names = implode(ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, array_map( |
| 304 | + function ($title, $storeName) { |
| 305 | + return $storeName . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR . $title; |
| 306 | + }, |
| 307 | + $optionTitles[$option->getOptionId()], |
| 308 | + array_keys($optionTitles[$option->getOptionId()]) |
| 309 | + )); |
| 310 | + return $names . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR |
| 311 | + . 'type' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR |
| 312 | + . $option->getType() . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR |
| 313 | + . 'required' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR |
| 314 | + . $option->getRequired(); |
280 | 315 | }
|
281 | 316 |
|
282 | 317 | /**
|
@@ -381,4 +416,83 @@ private function parseAdditionalAttributes($additionalAttributes)
|
381 | 416 | }
|
382 | 417 | return $preparedAttributes;
|
383 | 418 | }
|
| 419 | + |
| 420 | + /** |
| 421 | + * Get product options titles. |
| 422 | + * |
| 423 | + * Values for all store views (default) should be specified with 'name' key. |
| 424 | + * If user want to specify value or change existing for non default store views it should be specified with |
| 425 | + * 'name_' prefix and needed store view suffix. |
| 426 | + * |
| 427 | + * For example: |
| 428 | + * - 'name=All store views name' for all store views |
| 429 | + * - 'name_specific_store=Specific store name' for store view with 'specific_store' store code |
| 430 | + * |
| 431 | + * @param \Magento\Catalog\Model\Product $product |
| 432 | + * @return array |
| 433 | + */ |
| 434 | + private function getBundleOptionTitles(\Magento\Catalog\Model\Product $product): array |
| 435 | + { |
| 436 | + $optionCollections = $this->getProductOptionCollection($product); |
| 437 | + $optionsTitles = []; |
| 438 | + /** @var \Magento\Bundle\Model\Option $option */ |
| 439 | + foreach ($optionCollections->getItems() as $option) { |
| 440 | + $optionsTitles[$option->getId()]['name'] = $option->getTitle(); |
| 441 | + } |
| 442 | + $storeIds = $product->getStoreIds(); |
| 443 | + if (count($storeIds) > 1) { |
| 444 | + foreach ($storeIds as $storeId) { |
| 445 | + $optionCollections = $this->getProductOptionCollection($product, (int)$storeId); |
| 446 | + /** @var \Magento\Bundle\Model\Option $option */ |
| 447 | + foreach ($optionCollections->getItems() as $option) { |
| 448 | + $optionTitle = $option->getTitle(); |
| 449 | + if ($optionsTitles[$option->getId()]['name'] != $optionTitle) { |
| 450 | + $optionsTitles[$option->getId()]['name_' . $this->getStoreCodeById((int)$storeId)] = |
| 451 | + $optionTitle; |
| 452 | + } |
| 453 | + } |
| 454 | + } |
| 455 | + } |
| 456 | + return $optionsTitles; |
| 457 | + } |
| 458 | + |
| 459 | + /** |
| 460 | + * Get product options collection by provided product model. |
| 461 | + * |
| 462 | + * Set given store id to the product if it was defined (default store id will be set if was not). |
| 463 | + * |
| 464 | + * @param \Magento\Catalog\Model\Product $product $product |
| 465 | + * @param int $storeId |
| 466 | + * @return \Magento\Bundle\Model\ResourceModel\Option\Collection |
| 467 | + */ |
| 468 | + private function getProductOptionCollection( |
| 469 | + \Magento\Catalog\Model\Product $product, |
| 470 | + int $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID |
| 471 | + ): \Magento\Bundle\Model\ResourceModel\Option\Collection { |
| 472 | + $productSku = $product->getSku(); |
| 473 | + if (!isset($this->optionCollections[$productSku][$storeId])) { |
| 474 | + $product->unsetData($this->optionCollectionCacheKey); |
| 475 | + $product->setStoreId($storeId); |
| 476 | + $this->optionCollections[$productSku][$storeId] = $product->getTypeInstance() |
| 477 | + ->getOptionsCollection($product) |
| 478 | + ->setOrder('position', Collection::SORT_ORDER_ASC); |
| 479 | + } |
| 480 | + return $this->optionCollections[$productSku][$storeId]; |
| 481 | + } |
| 482 | + |
| 483 | + /** |
| 484 | + * Retrieve store code by it's ID. |
| 485 | + * |
| 486 | + * Collect store id in $storeIdToCode[] private variable if it was not initialized earlier. |
| 487 | + * |
| 488 | + * @param int $storeId |
| 489 | + * @return string |
| 490 | + */ |
| 491 | + private function getStoreCodeById(int $storeId): string |
| 492 | + { |
| 493 | + if (!isset($this->storeIdToCode[$storeId])) { |
| 494 | + $this->storeIdToCode[$storeId] = $this->storeManager->getStore($storeId)->getCode(); |
| 495 | + } |
| 496 | + return $this->storeIdToCode[$storeId]; |
| 497 | + } |
384 | 498 | }
|
0 commit comments