123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- declare(strict_types=1);
- namespace Magento\Bundle\Model\Option;
- use Magento\Bundle\Api\Data\OptionInterface;
- use Magento\Bundle\Model\ResourceModel\Option;
- use Magento\Catalog\Api\Data\ProductInterface;
- use Magento\Framework\EntityManager\MetadataPool;
- use Magento\Framework\Exception\CouldNotSaveException;
- use Magento\Bundle\Model\Product\Type;
- use Magento\Bundle\Api\ProductLinkManagementInterface;
- /**
- * Encapsulates logic for saving a bundle option, including coalescing the parent product's data.
- */
- class SaveAction
- {
- /**
- * @var Option
- */
- private $optionResource;
- /**
- * @var MetadataPool
- */
- private $metadataPool;
- /**
- * @var Type
- */
- private $type;
- /**
- * @var ProductLinkManagementInterface
- */
- private $linkManagement;
- /**
- * @param Option $optionResource
- * @param MetadataPool $metadataPool
- * @param Type $type
- * @param ProductLinkManagementInterface $linkManagement
- */
- public function __construct(
- Option $optionResource,
- MetadataPool $metadataPool,
- Type $type,
- ProductLinkManagementInterface $linkManagement
- ) {
- $this->optionResource = $optionResource;
- $this->metadataPool = $metadataPool;
- $this->type = $type;
- $this->linkManagement = $linkManagement;
- }
- /**
- * Manage the logic of saving a bundle option, including the coalescence of its parent product data.
- *
- * @param ProductInterface $bundleProduct
- * @param OptionInterface $option
- * @return OptionInterface
- * @throws CouldNotSaveException
- * @throws \Exception
- */
- public function save(ProductInterface $bundleProduct, OptionInterface $option)
- {
- $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
- $option->setStoreId($bundleProduct->getStoreId());
- $parentId = $bundleProduct->getData($metadata->getLinkField());
- $option->setParentId($parentId);
- $optionId = $option->getOptionId();
- $linksToAdd = [];
- $optionCollection = $this->type->getOptionsCollection($bundleProduct);
- $optionCollection->setIdFilter($option->getOptionId());
- $optionCollection->setProductLinkFilter($parentId);
- /** @var \Magento\Bundle\Model\Option $existingOption */
- $existingOption = $optionCollection->getFirstItem();
- if (!$optionId || $existingOption->getParentId() != $parentId) {
- //If option ID is empty or existing option's parent ID is different
- //we'd need a new ID for the option.
- $option->setOptionId(null);
- $option->setDefaultTitle($option->getTitle());
- if (is_array($option->getProductLinks())) {
- $linksToAdd = $option->getProductLinks();
- }
- } else {
- if (!$existingOption->getOptionId()) {
- throw new NoSuchEntityException(
- __("The option that was requested doesn't exist. Verify the entity and try again.")
- );
- }
- $option->setData(array_merge($existingOption->getData(), $option->getData()));
- $this->updateOptionSelection($bundleProduct, $option);
- }
- try {
- $this->optionResource->save($option);
- } catch (\Exception $e) {
- throw new CouldNotSaveException(__("The option couldn't be saved."), $e);
- }
- /** @var \Magento\Bundle\Api\Data\LinkInterface $linkedProduct */
- foreach ($linksToAdd as $linkedProduct) {
- $this->linkManagement->addChild($bundleProduct, $option->getOptionId(), $linkedProduct);
- }
- $bundleProduct->setIsRelationsChanged(true);
- return $option;
- }
- /**
- * Update option selections
- *
- * @param \Magento\Catalog\Api\Data\ProductInterface $product
- * @param \Magento\Bundle\Api\Data\OptionInterface $option
- * @return void
- */
- private function updateOptionSelection(ProductInterface $product, OptionInterface $option)
- {
- $optionId = $option->getOptionId();
- $existingLinks = $this->linkManagement->getChildren($product->getSku(), $optionId);
- $linksToAdd = [];
- $linksToUpdate = [];
- $linksToDelete = [];
- if (is_array($option->getProductLinks())) {
- $productLinks = $option->getProductLinks();
- foreach ($productLinks as $productLink) {
- if (!$productLink->getId() && !$productLink->getSelectionId()) {
- $linksToAdd[] = $productLink;
- } else {
- $linksToUpdate[] = $productLink;
- }
- }
- /** @var \Magento\Bundle\Api\Data\LinkInterface[] $linksToDelete */
- $linksToDelete = $this->compareLinks($existingLinks, $linksToUpdate);
- }
- foreach ($linksToUpdate as $linkedProduct) {
- $this->linkManagement->saveChild($product->getSku(), $linkedProduct);
- }
- foreach ($linksToDelete as $linkedProduct) {
- $this->linkManagement->removeChild(
- $product->getSku(),
- $option->getOptionId(),
- $linkedProduct->getSku()
- );
- }
- foreach ($linksToAdd as $linkedProduct) {
- $this->linkManagement->addChild($product, $option->getOptionId(), $linkedProduct);
- }
- }
- /**
- * Compute the difference between given arrays.
- *
- * @param \Magento\Bundle\Api\Data\LinkInterface[] $firstArray
- * @param \Magento\Bundle\Api\Data\LinkInterface[] $secondArray
- *
- * @return array
- */
- private function compareLinks(array $firstArray, array $secondArray)
- {
- $result = [];
- $firstArrayIds = [];
- $firstArrayMap = [];
- $secondArrayIds = [];
- foreach ($firstArray as $item) {
- $firstArrayIds[] = $item->getId();
- $firstArrayMap[$item->getId()] = $item;
- }
- foreach ($secondArray as $item) {
- $secondArrayIds[] = $item->getId();
- }
- foreach (array_diff($firstArrayIds, $secondArrayIds) as $id) {
- $result[] = $firstArrayMap[$id];
- }
- return $result;
- }
- }
|