165 lines
6.4 KiB
PHP
165 lines
6.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\Cart\Controller\Mix;
|
|
|
|
use Magento\Catalog\Api\ProductRepositoryInterface;
|
|
use Magento\Catalog\Model\Product;
|
|
use Magento\Checkout\Model\Cart;
|
|
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
|
|
use Magento\Framework\App\Action\Action;
|
|
use Magento\Framework\App\Action\Context;
|
|
use Magento\Framework\App\Action\HttpPostActionInterface;
|
|
use Magento\Framework\Controller\Result\Redirect;
|
|
use Magento\Framework\DataObject;
|
|
use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Store\Model\StoreManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class Add extends Action implements HttpPostActionInterface
|
|
{
|
|
public function __construct(
|
|
Context $context,
|
|
private readonly FormKeyValidator $formKeyValidator,
|
|
private readonly ProductRepositoryInterface $productRepository,
|
|
private readonly StoreManagerInterface $storeManager,
|
|
private readonly Cart $cart,
|
|
private readonly LoggerInterface $logger
|
|
) {
|
|
parent::__construct($context);
|
|
}
|
|
|
|
public function execute(): Redirect
|
|
{
|
|
$redirect = $this->resultRedirectFactory->create();
|
|
$backUrl = (string)$this->_redirect->getRefererUrl();
|
|
|
|
if (!$this->formKeyValidator->validate($this->getRequest())) {
|
|
$this->messageManager->addErrorMessage(__('Your session has expired. Please try again.'));
|
|
return $redirect->setUrl($backUrl);
|
|
}
|
|
|
|
try {
|
|
$parentProduct = $this->getParentProduct();
|
|
$items = $this->getRequestedItems();
|
|
$this->validateChildren($parentProduct, array_keys($items));
|
|
$configurableAttributes = $parentProduct->getTypeInstance()
|
|
->getConfigurableAttributes($parentProduct);
|
|
$itemsToAdd = $items;
|
|
$isSyncMode = (string)$this->getRequest()->getParam('mix_mode') === 'sync';
|
|
|
|
if ($isSyncMode) {
|
|
$updates = [];
|
|
foreach ($this->cart->getQuote()->getAllVisibleItems() as $quoteItem) {
|
|
if ((int)$quoteItem->getProductId() !== (int)$parentProduct->getId()) {
|
|
continue;
|
|
}
|
|
|
|
$simpleProductOption = $quoteItem->getOptionByCode('simple_product');
|
|
$childProductId = (int)($simpleProductOption?->getProduct()?->getId() ?: 0);
|
|
if ($childProductId > 0 && isset($items[$childProductId])) {
|
|
$updates[(int)$quoteItem->getId()] = ['qty' => $items[$childProductId]];
|
|
unset($itemsToAdd[$childProductId]);
|
|
} else {
|
|
$updates[(int)$quoteItem->getId()] = ['remove' => true];
|
|
}
|
|
}
|
|
if ($updates) {
|
|
$this->cart->updateItems($updates);
|
|
}
|
|
}
|
|
|
|
foreach ($itemsToAdd as $childProductId => $quantity) {
|
|
$childProduct = $this->productRepository->getById(
|
|
$childProductId,
|
|
false,
|
|
(int)$this->storeManager->getStore()->getId()
|
|
);
|
|
if (!$childProduct->isSaleable()) {
|
|
throw new LocalizedException(
|
|
__('%1 is currently unavailable.', $childProduct->getName())
|
|
);
|
|
}
|
|
|
|
$superAttributes = [];
|
|
foreach ($configurableAttributes as $configurableAttribute) {
|
|
$attribute = $configurableAttribute->getProductAttribute();
|
|
$superAttributes[(int)$attribute->getId()] = $childProduct->getData(
|
|
$attribute->getAttributeCode()
|
|
);
|
|
}
|
|
|
|
$this->cart->addProduct(clone $parentProduct, new DataObject([
|
|
'qty' => $quantity,
|
|
'super_attribute' => $superAttributes,
|
|
]));
|
|
}
|
|
|
|
$this->cart->save();
|
|
$totalQuantity = array_sum($items);
|
|
$this->messageManager->addSuccessMessage($isSyncMode
|
|
? __('You updated %1 variants (%2 items) in your shopping cart.', count($items), $totalQuantity)
|
|
: __('You added %1 variants (%2 items) to your shopping cart.', count($items), $totalQuantity));
|
|
} catch (LocalizedException $exception) {
|
|
$this->messageManager->addErrorMessage($exception->getMessage());
|
|
} catch (\Throwable $exception) {
|
|
$this->logger->critical($exception);
|
|
$this->messageManager->addErrorMessage(
|
|
__('We can\'t add these items to your shopping cart right now.')
|
|
);
|
|
}
|
|
|
|
return $redirect->setUrl($backUrl);
|
|
}
|
|
|
|
private function getParentProduct(): Product
|
|
{
|
|
$productId = (int)$this->getRequest()->getParam('product');
|
|
$product = $this->productRepository->getById(
|
|
$productId,
|
|
false,
|
|
(int)$this->storeManager->getStore()->getId()
|
|
);
|
|
if ($product->getTypeId() !== Configurable::TYPE_CODE || !$product->isSaleable()) {
|
|
throw new LocalizedException(__('This product is not available for mix purchasing.'));
|
|
}
|
|
|
|
return $product;
|
|
}
|
|
|
|
/** @return array<int, int> */
|
|
private function getRequestedItems(): array
|
|
{
|
|
$requestItems = $this->getRequest()->getParam('mix_items', []);
|
|
$items = [];
|
|
|
|
if (is_array($requestItems)) {
|
|
foreach ($requestItems as $childProductId => $quantity) {
|
|
$childProductId = (int)$childProductId;
|
|
$quantity = (int)$quantity;
|
|
if ($childProductId > 0 && $quantity > 0) {
|
|
$items[$childProductId] = $quantity;
|
|
}
|
|
}
|
|
}
|
|
if (!$items) {
|
|
throw new LocalizedException(__('Please choose at least one variant and quantity.'));
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
|
|
/** @param int[] $childProductIds */
|
|
private function validateChildren(Product $parentProduct, array $childProductIds): void
|
|
{
|
|
$allowedIds = array_map(
|
|
'intval',
|
|
$parentProduct->getTypeInstance()->getUsedProductIds($parentProduct)
|
|
);
|
|
if (array_diff($childProductIds, $allowedIds)) {
|
|
throw new LocalizedException(__('One or more selected variants do not belong to this product.'));
|
|
}
|
|
}
|
|
}
|