0

I modify phtml of product to show all possible sizes (size is a custom attribute) in a table with possibility to choose by user how many products of each size he wants to add to cart. here how it looks on product view

Let's assume, that user wants to buy 2 items of Art.38013 and 1 item of Art.38014. Request body will look like:

selected_configurable_option: 
related_product: 
item: 18145
form_key: vj1sQTSc2Kyq3Eay
super_attribute[93]: 6598
super_attribute[143][6707]: 2
super_attribute[143][6714]: 1
super_attribute[143][6715]: 0

93 is color attribute id 143 is size attribute id 9598 is color option id 6707, 6714, 6715 are sizes option id 2,1,0 are amount of each size. Now if I check my cart page it will contain only 3 products of Art.38013. So it looks like script is adding products in wrong way, but if I add the items in separate requests it will work just fine. Okay, I thought, that I can get configurable product children by attributes and add them to cart separately, but in this way cart contain proper amount of products with proper ids, but there is no product attributes shown. I check view file of the cart (vendor/magento/module-checkout/view/frontend/templates/cart/item/default.phtml) and looks like in this way cart product does not have options - no idea why. Okay, here is my code snippet

/**
 *
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Vlncode\Checkout\Controller\Cart;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Checkout\Model\Cart as CustomerCart;
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Exception\NoSuchEntityException;

/**
 * Controller for processing add to cart action.
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Add extends \Magento\Checkout\Controller\Cart implements HttpPostActionInterface
{
    /**
     * @var ProductRepositoryInterface
     */
    protected $productRepository;

    /**
     * @var
     */
    protected $storeId;

    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Checkout\Model\Session $checkoutSession
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator
     * @param CustomerCart $cart
     * @param ProductRepositoryInterface $productRepository
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator,
        CustomerCart $cart,
        ProductRepositoryInterface $productRepository
    ) {
        parent::__construct(
            $context,
            $scopeConfig,
            $checkoutSession,
            $storeManager,
            $formKeyValidator,
            $cart
        );
        $this->productRepository = $productRepository;
        $this->storeId = $this->_objectManager->get(
            \Magento\Store\Model\StoreManagerInterface::class
        )->getStore()->getId();
    }

    /**
     * Initialize product instance from request data
     *
     * @return \Magento\Catalog\Model\Product|false
     */
    protected function _initProduct()
    {
        $productId = (int)$this->getRequest()->getParam('product');
        if ($productId) {
            try {
                return $this->productRepository->getById($productId, false, $this->storeId);
            } catch (NoSuchEntityException $e) {
                return false;
            }
        }
        return false;
    }

    /**
     * @param array $params
     * @return array
     * @throws NoSuchEntityException
     */
    final private function extractParamsForConfigurable(array $params): array
    {
        $keys = [
            'related_product',
            'form_key',
            'product',
//            'item',
        ];
        $newParams = [];
        foreach ($params as $key => $value) {
            if (in_array($key, $keys)) {
                $newParams[$key] = $value;
            }
        }

        $products = [];
        if (isset($params['super_attribute'])) {
            $uniqueAttributes = array_unique(array_keys($params['super_attribute']));
            $superAttributes = $params['super_attribute'];
            $products = [];
            $simpleAttributes = [];
            // 1. Get all non array elements to another array, left in array only arrays
            foreach ($uniqueAttributes as $superAttributeId) {
                if (!is_array($superAttributes[$superAttributeId])) {
                    $simpleAttributes[] = [$superAttributeId => $superAttributes[$superAttributeId]];
                    unset($superAttributes[$superAttributeId]);
                }
            }

            // 2. iterate trough complex attribute and create all possible modifications
            foreach ($superAttributes as $attributeId => $sizes) {
                foreach ($sizes as $sizeId => $qty) {
                    if ($qty == 0) {
                        continue;
                    }
                    if (!empty($simpleAttributes)) {
                        // for complex products with tier prices and simple attributes
                        foreach ($simpleAttributes as $simpleAttributeValue) {
                            $tmpProduct = $newParams;
                            $simpleProductKey = array_key_first($simpleAttributeValue);
                            $tmpProduct['super_attribute'][$simpleProductKey] = $simpleAttributeValue[$simpleProductKey];
                            $tmpProduct['super_attribute'][$attributeId] = (string)$sizeId;
                            $tmpProduct['qty'] = $qty;
                            $products [] = $tmpProduct;
                        }
                    } else { // just for products with different size prices
                        $tmpProduct = $newParams;
                        $tmpProduct['super_attribute'][$attributeId] = (string)$sizeId;
                        $tmpProduct['qty'] = $qty;
                        $products [] = $tmpProduct;
                    }
                }
            }
        }
        return $products;
    }

    /**
     * Add products one by one to cart
     * @param $params
     * @return \Magento\Framework\Controller\Result\Redirect|Add
     * @throws NoSuchEntityException
     */
    final private function executeConfigurable($params)
    {
        $products = $this->extractParamsForConfigurable($params);

        try {
            foreach ($products as $productParams) {
                $product = null;
                $product = $this->productRepository->getById($productParams['product'], false, $this->storeId);
//                $productParams['related_product'] = $product->getTypeInstance()->getProductByAttributes($productParams['super_attribute'], $product)->getId();
//                $productParams['product'] = $product->getId();

                if (isset($productParams['qty'])) {
                    $filter = new \Zend_Filter_LocalizedToNormalized(
                        ['locale' => $this->_objectManager->get(
                            \Magento\Framework\Locale\ResolverInterface::class
                        )->getLocale()]
                    );
                    $productParams['qty'] = $filter->filter($productParams['qty']);
                }

                $related = $productParams['related_product'];

                /**
                 * Check product availability
                 */
                if (!$product) {
                    return $this->goBack();
                }

                $this->cart->addProduct($product, $productParams);
                if (!empty($related)) {
                    die(var_dump($related));
                    $this->cart->addProductsByIds(explode(',', $related));
                }
            }
            $this->cart->save();

            /**
             * @todo remove wishlist observer \Magento\Wishlist\Observer\AddToCart
             */
            $this->_eventManager->dispatch(
                'checkout_cart_add_product_complete',
                ['product' => $product, 'request' => $this->getRequest(), 'response' => $this->getResponse()]
            );

            if (!$this->_checkoutSession->getNoCartRedirect(true)) {
                if (!$this->cart->getQuote()->getHasError()) {
                    if ($this->shouldRedirectToCart()) {
                        $message = __(
                            'You added %1 to your shopping cart.',
                            $product->getName()
                        );
                        $this->messageManager->addSuccessMessage($message);
                    } else {
                        $this->messageManager->addComplexSuccessMessage(
                            'addCartSuccessMessage',
                            [
                                'product_name' => $product->getName(),
                                'cart_url' => $this->getCartUrl(),
                            ]
                        );
                    }
                }
                return $this->goBack(null, $product);
            }
        } catch (\Magento\Framework\Exception\LocalizedException $e) {
            if ($this->_checkoutSession->getUseNotice(true)) {
                $this->messageManager->addNoticeMessage(
                    $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($e->getMessage())
                );
            } else {
                $messages = array_unique(explode("\n", $e->getMessage()));
                foreach ($messages as $message) {
                    $this->messageManager->addErrorMessage(
                        $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($message)
                    );
                }
            }

            $url = $this->_checkoutSession->getRedirectUrl(true);

            if (!$url) {
                $url = $this->_redirect->getRedirectUrl($this->getCartUrl());
            }

            return $this->goBack($url);
        } catch (\Exception $e) {
            $this->messageManager->addExceptionMessage(
                $e,
                __('We can\'t add this item to your shopping cart right now.')
            );
            $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
            return $this->goBack();
        }
    }

    /**
     * Add product to shopping cart action
     *
     * @return \Magento\Framework\Controller\Result\Redirect
     * @throws NoSuchEntityException
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     */
    public function execute()
    {
        if (!$this->_formKeyValidator->validate($this->getRequest())) {
            $this->messageManager->addErrorMessage(
                __('Your session has expired')
            );
            return $this->resultRedirectFactory->create()->setPath('*/*/');
        }

        $params = $this->getRequest()->getParams();

        $product = $this->_initProduct();
        if ($product->getTypeId() === 'configurable') {
            return $this->executeConfigurable($params);
        }

        return $this->addToCart($product, $params);
    }

    /**
     * @param $product
     * @param $params
     * @return $this|\Magento\Framework\Controller\Result\Redirect
     */
    final private function addToCart($product, $params)
    {
        try {
            if (isset($params['qty'])) {
                $filter = new \Zend_Filter_LocalizedToNormalized(
                    ['locale' => $this->_objectManager->get(
                        \Magento\Framework\Locale\ResolverInterface::class
                    )->getLocale()]
                );
                $params['qty'] = $filter->filter($params['qty']);
            }

            $related = $this->getRequest()->getParam('related_product');

            /**
             * Check product availability
             */
            if (!$product) {
                return $this->goBack();
            }

            $this->cart->addProduct($product, $params);
            if (!empty($related)) {
                $this->cart->addProductsByIds(explode(',', $related));
            }

            $this->cart->save();

            /**
             * @todo remove wishlist observer \Magento\Wishlist\Observer\AddToCart
             */
            $this->_eventManager->dispatch(
                'checkout_cart_add_product_complete',
                ['product' => $product, 'request' => $this->getRequest(), 'response' => $this->getResponse()]
            );

            if (!$this->_checkoutSession->getNoCartRedirect(true)) {
                if (!$this->cart->getQuote()->getHasError()) {
                    if ($this->shouldRedirectToCart()) {
                        $message = __(
                            'You added %1 to your shopping cart.',
                            $product->getName()
                        );
                        $this->messageManager->addSuccessMessage($message);
                    } else {
                        $this->messageManager->addComplexSuccessMessage(
                            'addCartSuccessMessage',
                            [
                                'product_name' => $product->getName(),
                                'cart_url' => $this->getCartUrl(),
                            ]
                        );
                    }
                }
                return $this->goBack(null, $product);
            }
        } catch (\Magento\Framework\Exception\LocalizedException $e) {
            if ($this->_checkoutSession->getUseNotice(true)) {
                $this->messageManager->addNoticeMessage(
                    $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($e->getMessage())
                );
            } else {
                $messages = array_unique(explode("\n", $e->getMessage()));
                foreach ($messages as $message) {
                    $this->messageManager->addErrorMessage(
                        $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($message)
                    );
                }
            }

            $url = $this->_checkoutSession->getRedirectUrl(true);

            if (!$url) {
                $url = $this->_redirect->getRedirectUrl($this->getCartUrl());
            }

            return $this->goBack($url);
        } catch (\Exception $e) {
            $this->messageManager->addExceptionMessage(
                $e,
                __('We can\'t add this item to your shopping cart right now.')
            );
            $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
            return $this->goBack();
        }
    }

    /**
     * Resolve response
     *
     * @param string $backUrl
     * @param \Magento\Catalog\Model\Product $product
     * @return $this|\Magento\Framework\Controller\Result\Redirect
     */
    protected function goBack($backUrl = null, $product = null)
    {
        if (!$this->getRequest()->isAjax()) {
            return parent::_goBack($backUrl);
        }

        $result = [];

        if ($backUrl || $backUrl = $this->getBackUrl()) {
            $result['backUrl'] = $backUrl;
        } else {
            if ($product && !$product->getIsSalable()) {
                $result['product'] = [
                    'statusText' => __('Out of stock')
                ];
            }
        }

        $this->getResponse()->representJson(
            $this->_objectManager->get(\Magento\Framework\Json\Helper\Data::class)->jsonEncode($result)
        );
    }

    /**
     * Returns cart url
     *
     * @return string
     */
    private function getCartUrl()
    {
        return $this->_url->getUrl('checkout/cart', ['_secure' => true]);
    }

    /**
     * Is redirect should be performed after the product was added to cart.
     *
     * @return bool
     */
    private function shouldRedirectToCart()
    {
        return $this->_scopeConfig->isSetFlag(
            'checkout/cart/redirect_to_cart',
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
        );
    }
}

Take a look on part from line 153. For better understanding here is value of variable $products from line 153

array(2) {
  [0]=>
  array(5) {
    ["product"]=>
    string(5) "18145"
    ["related_product"]=>
    string(0) ""
    ["form_key"]=>
    string(16) "vj1sQTSc2Kyq3EAy"
    ["super_attribute"]=>
    array(2) {
      [93]=>
      string(4) "6598"
      [143]=>
      string(4) "6707"
    }
    ["qty"]=>
    string(1) "2"
  }
  [1]=>
  array(5) {
    ["product"]=>
    string(5) "18145"
    ["related_product"]=>
    string(0) ""
    ["form_key"]=>
    string(16) "vj1sQTSc2Kyq3EAy"
    ["super_attribute"]=>
    array(2) {
      [93]=>
      string(4) "6598"
      [143]=>
      string(4) "6714"
    }
    ["qty"]=>
    string(1) "1"
  }
}

Your Answer

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

Browse other questions tagged or ask your own question.