<?php declare(strict_types=1);
namespace Atl\ProductConfigurator\Subscriber;
use Atl\ProductConfigurator\Core\Content\ProductConfigurator\ProductConfiguratorEntity;
use Atl\ProductConfigurator\Core\Content\ProductConfigurator\SalesChannel\Price\PriceService;
use Atl\ProductConfigurator\Migration\Migration1628124328ProductExtension;
use Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Product\SalesChannel\Price\ProductPriceCalculator;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class LineItemAddedSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private $productRepository;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var PriceService
*/
private $priceService;
/**
* @var ProductPriceCalculator
*/
private $productPriceCalculator;
public function __construct(
EntityRepositoryInterface $productRepository,
RequestStack $requestStack,
PriceService $priceService,
ProductPriceCalculator $productPriceCalculator
)
{
$this->productRepository = $productRepository;
$this->requestStack = $requestStack;
$this->priceService = $priceService;
$this->productPriceCalculator = $productPriceCalculator;
}
public static function getSubscribedEvents(): array
{
return [
BeforeLineItemAddedEvent::class => "onLineItemAdded"
];
}
/**
* @param BeforeLineItemAddedEvent $event
*/
public function onLineItemAdded(BeforeLineItemAddedEvent $event): void
{
$lineItems = $this->requestStack->getMainRequest()->request->get("lineItems");
// Prevent checkout login error
if (empty($lineItems)) {
return;
}
foreach ($lineItems as $lineItem) {
if (empty($lineItem["atlProductConfigurator"])) {
continue;
}
if (!$lineItem['productConfiguration']) {
// TODO: Fix stackable of non-configured products
$event->getLineItem()->setId(Uuid::randomHex());
continue;
}
// Filter empty inputs
$inputFields = array_filter($lineItem["atlProductConfigurator"]);
$productConfigurator = $this->loadProductConfigurator($event);
// Build payload
$payload = [];
$position = 0;
foreach ($inputFields as $key => $input) {
if ($key === 'dropdown') {
$label = $this->getLabelForDropdown($productConfigurator);
} else {
$label = $this->getLabelForTextField($key, $productConfigurator);
}
$payload[$key] = [
"label" => $label,
"value" => $input,
"position" => $position
];
$position += 1;
}
// Create new line item to avoid stacking when added
$event->getLineItem()->setId(Uuid::randomHex());
$event->getLineItem()->setPayloadValue('atlProductConfigurator', $payload);
if (empty($productConfigurator->getCalculatedPrice())) {
return;
}
// Set price
$event->getLineItem()->setPayloadValue('atlProductConfiguratorPrice', $productConfigurator->getCalculatedPrice()->getUnitPrice());
}
}
/**
* @param BeforeLineItemAddedEvent $event
* @return ProductConfiguratorEntity
*/
private function loadProductConfigurator(BeforeLineItemAddedEvent $event): ProductConfiguratorEntity
{
$productId = $event->getLineItem()->getId();
$criteria = new Criteria([$productId]);
/** @var ProductEntity $field */
$product = $this->productRepository->search($criteria, $event->getContext())->first();
$this->productPriceCalculator->calculate([$product], $event->getSalesChannelContext());
$event->getLineItem()->setPayloadValue('atlProductConfiguratorProductPrice', $product->calculatedPrice->getUnitPrice());
$productConfigurator = $product->getExtension(Migration1628124328ProductExtension::PRODUCT_EXTENSION);
$this->priceService->calculatePrice($productConfigurator, $event->getSalesChannelContext());
return $productConfigurator;
}
/**
* @param ProductConfiguratorEntity $productConfigurator
* @return string
*/
public function getLabelForDropdown(ProductConfiguratorEntity $productConfigurator): string
{
$dropdownLabel = $productConfigurator->getDropdownLabel();
if (empty($dropdownLabel)) {
return '';
}
return $dropdownLabel;
}
/**
* @param string $id
* @param ProductConfiguratorEntity $productConfigurator
* @return string
*/
public function getLabelForTextField(string $id, ProductConfiguratorEntity $productConfigurator): string
{
$field = $productConfigurator->getAtlProductConfiguratorFields()->getElements()[$id];
return $field->getTranslated()['label'];
}
}