Question

I am facing some problems when trying to add to cart multiple configurable products in 1 single request

We have tuned product list page, to add the required form values for this kind of request (configurable child options, etc...) and this values are sent to a custom controller action

This is the controller code

<?php
namespace Vendor\Module\Controller\Add;

class Cart extends \Magento\Framework\App\Action\Action
{
    protected $_cart;
    protected $productRepository;
    protected $formKeyValidator;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Checkout\Model\Cart $cart,
        \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
        \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator
    ) {

        $this->_cart = $cart;
        $this->productRepository = $productRepository;
        $this->_formKeyValidator = $formKeyValidator;

        return parent::__construct($context);
    }

    public function execute()
    {
        if (!$this->_formKeyValidator->validate($this->getRequest())) {
            return $this->resultRedirectFactory->create()->setPath('*/*/');
        }

        $qtys       = $this->getRequest()->getParam('qty');
        $childIds   = $this->getRequest()->getParam('child_ids');

        $add = array();
        foreach ($qtys as $parentId => $array) {
            if (is_array($array)) {
                foreach ($array as $attributeId => $child) {
                    foreach ($child as $childId => $value) {
                        if ($value != 0) {
                            $add[$parentId][$attributeId][$childId] = $value;
                        }
                    }
                }
            } else {
                // simple products?
                // @todo
            }
        }

        foreach ($add as $productId => $data) {
            $_product = $this->productRepository->getById($productId);

            foreach ($data as $attributeId => $child) {
                foreach ($child as $childId => $qty) {
                    $options = array(
                        $attributeId => $childId,
                    );

                    $params = array(
                        'form_key' => $this->getRequest()->getParam('form_key'),
                        'product' => $productId,
                        'super_attribute' => $options,
                        'qty' => $qty,
                        'selected_configurable_option' => $childIds[$productId][$attributeId][$childId],
                    );
                    $this->_cart->addProduct($_product, $params);
                }
            }
        }
        $this->_cart->save();
        return $this->resultRedirectFactory->create()->setPath('checkout/cart');
    }
}

This are the results I am getting

  • when adding different children of same configurable product only the first is being added to cart (with qtys of others being added to that first child)
  • when adding different configurable products (with any children) product prices are displayed correctly only in the first configurable product... the others show price 0€

Assuming the data in both $qtys & $childIds arrays are correct (I have validated them against data sent from a configurable product view add to cart request, and they seem ok), can you lead me to the error in the controller code, or any missing code required to be added?

Was it helpful?

Solution

As reported here https://magento.stackexchange.com/a/110666/3566, problem was we have to create each time new product object

I have tried different ways, trying to avoid using $this->_objectManager

Using \Magento\Catalog\Model\ProductFactory was the only way to make that work

So, apart from adding the new dependency in constructor, with this code changes...

    foreach ($add as $productId => $data) {
        foreach ($data as $attributeId => $child) {
            foreach ($child as $childId => $qty) {
                // @see https://magento.stackexchange.com/a/110666/3566 -> reload product
                $_product = $this->productFactory->create()->setStoreId($storeId)->load($productId);
                $options = array(
                    $attributeId => $childId,
                );

                $params = array(
                    'form_key' => $this->getRequest()->getParam('form_key'),
                    'product' => $productId,
                    'super_attribute' => $options,
                    'qty' => $qty,
                    'selected_configurable_option' => $childIds[$productId][$attributeId][$childId],
                );

                $this->_cart->addProduct($_product, $params);
                $this->_cart->save();
            }
        }
    }

All products are being added to cart correctly, although I have seen some pricing issues (only first configurable product has the right price & the others print 0€), but that's another story

OTHER TIPS

You need to keep cart save logic outside the foreach loop, So your price issue will be resolved,

    foreach ($add as $productId => $data) {
        foreach ($data as $attributeId => $child) {
            foreach ($child as $childId => $qty) {
                // @see https://magento.stackexchange.com/a/110666/3566 -> reload product
                $_product = $this->productFactory->create()->setStoreId($storeId)->load($productId);
                $options = array(
                    $attributeId => $childId,
                );

                $params = array(
                    'form_key' => $this->getRequest()->getParam('form_key'),
                    'product' => $productId,
                    'super_attribute' => $options,
                    'qty' => $qty,
                    'selected_configurable_option' => $childIds[$productId][$attributeId][$childId],
                );

                $this->_cart->addProduct($_product, $params);
            }
        }
    }
  $this->_cart->save();
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top