3

I have created a custom product like bundle product, which has all bundle product attributes. Problem is that its bundle options are not saving in ver 2.3.x, while on all other versions it working fine, the product page is keep loading and loading when I try to save bundle options, without bundle options the product is saving fine.

I have tried to increase the execution time, memory, etc of server, but the problem still exists.

Anyone can help me out of this, thanks in advance.

2
  • Did you create like custom product type same like bundle product?
    – aravind
    Feb 25 '20 at 11:51
  • Have you find solution to save the custom product type?
    – aravind
    Feb 25 '20 at 11:51
0

I was trying to build a custom product type in 2.3.4 with the same issue and found the solution was actually in the saving of the options specifically after much debugging the following should help if anyone else has this problem.

I would start by referencing this post: Extending bundle product in custom type ends up without "add option" button

Assuming you have gone through and done everything to create a custom product type you will need to do the following additional step.

  1. In etc/di.xml add
preference for="Magento\Bundle\Model\SaveHandler" type="vendor\package\Model\SaveHandler"
  1. Next add the model in your package for saveHandler app/code/vendor/package/Model/SaveHandler.php
optionRepository = $optionRepository;
        $this->productLinkManagement = $productLinkManagement;
        $this->optionSave = $optionSave;
        $this->metadataPool = $metadataPool
            ?: ObjectManager::getInstance()->get(MetadataPool::class);
    }

    /**
     * Perform action on Bundle product relation/extension attribute
     *
     * @param object $entity
     * @param array $arguments
     *
     * @return ProductInterface|object
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function execute($entity, $arguments = [])
    {
        /** @var \Magento\Bundle\Api\Data\OptionInterface[] $bundleProductOptions */
        $bundleProductOptions = $entity->getExtensionAttributes()->getBundleProductOptions() ?: [];
        //Only processing bundle products.
        if (($entity->getTypeId() !== Type::TYPE_CODE && $entity->getTypeId() !== CustomType::TYPE_CODE) || empty($bundleProductOptions)) {
            return $entity;
        }

        $existingBundleProductOptions = $this->optionRepository->getList($entity->getSku());
        $existingOptionsIds = !empty($existingBundleProductOptions)
            ? $this->getOptionIds($existingBundleProductOptions)
            : [];
        $optionIds = !empty($bundleProductOptions)
            ? $this->getOptionIds($bundleProductOptions)
            : [];

        if (!$entity->getCopyFromView()) {
            $this->processRemovedOptions($entity, $existingOptionsIds, $optionIds);
            $newOptionsIds = array_diff($optionIds, $existingOptionsIds);
            $this->saveOptions($entity, $bundleProductOptions, $newOptionsIds);
        } else {
            //save only labels and not selections + product links
            $this->saveOptions($entity, $bundleProductOptions);
            $entity->setCopyFromView(false);
        }

        return $entity;
    }

    /**
     * Remove option product links
     *
     * @param string $entitySku
     * @param \Magento\Bundle\Api\Data\OptionInterface $option
     * @return void
     */
    protected function removeOptionLinks($entitySku, $option)
    {
        $links = $option->getProductLinks();
        if (!empty($links)) {
            foreach ($links as $link) {
                $this->productLinkManagement->removeChild($entitySku, $option->getId(), $link->getSku());
            }
        }
    }

    /**
     * Perform save for all options entities.
     *
     * @param object $entity
     * @param array $options
     * @param array $newOptionsIds
     * @return void
     */
    private function saveOptions($entity, array $options, array $newOptionsIds = []): void
    {
        foreach ($options as $option) {
            if (in_array($option->getOptionId(), $newOptionsIds, true)) {
                $option->setOptionId(null);
            }

            $this->optionSave->save($entity, $option);
        }
    }

    /**
     * Get options ids from array of the options entities.
     *
     * @param array $options
     * @return array
     */
    private function getOptionIds(array $options): array
    {
        $optionIds = [];

        if (!empty($options)) {
            /** @var \Magento\Bundle\Api\Data\OptionInterface $option */
            foreach ($options as $option) {
                if ($option->getOptionId()) {
                    $optionIds[] = $option->getOptionId();
                }
            }
        }

        return $optionIds;
    }

    /**
     * Removes old options that no longer exists.
     *
     * @param ProductInterface $entity
     * @param array $existingOptionsIds
     * @param array $optionIds
     * @return void
     */
    private function processRemovedOptions(ProductInterface $entity, array $existingOptionsIds, array $optionIds): void
    {
        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
        $parentId = $entity->getData($metadata->getLinkField());
        foreach (array_diff($existingOptionsIds, $optionIds) as $optionId) {
            $option = $this->optionRepository->get($entity->getSku(), $optionId);
            $option->setParentId($parentId);
            $this->removeOptionLinks($entity->getSku(), $option);
            $this->optionRepository->delete($option);
        }
    }
}

The main changes you need to make sure you implement are:

use Magento\Bundle\Model\Product\Type as Type; use ForeverCompanies\DynamicBundle\Model\Product\Type as DynamicType;

AND

if (($entity->getTypeId() !== Type::TYPE_CODE && $entity->getTypeId() !== DynamicType::TYPE_CODE) || empty($bundleProductOptions)) { return $entity; }

This allows the options to save when you have created a custom product type by referencing the base and custom class types. I'm not an expert in M2 yet, but something tells me the issue is actually more from the way the extended product extension is made because the instance of type should inherit from the custom type not the core module I would think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.