<?php
declare(strict_types=1);
/**
* @copyright 2020 Crehler Sp. z o. o.
* @link https://crehler.com/
* @support support@crehler.com
*
* @author Mateusz FlasiĆski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Crehler\Catalog\Subscriber;
use Crehler\Catalog\Entity\Catalog\Aggregate\CatalogPage\ProductDotDefinition;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PageProductWrittenSubscriber implements EventSubscriberInterface
{
private EntityRepositoryInterface $catalogProductDotRepository;
private array $dotsCache;
private array $positionsCache;
public function __construct(EntityRepositoryInterface $catalogProductDotRepository)
{
$this->catalogProductDotRepository = $catalogProductDotRepository;
$this->dotsCache = [];
$this->positionsCache = [];
}
public static function getSubscribedEvents()
{
return ['catalog_page_product.written' => 'onProductWritten'];
}
public function onProductWritten(EntityWrittenEvent $event): void
{
$mapping = [];
$ids = [];
foreach ($event->getWriteResults() as $entityWriteResult) {
$payload = $entityWriteResult->getPayload();
if (isset($payload['catalogPageId'])) {
$catalogPageId = $payload['catalogPageId'];
} else {
$catalogPageId = null;
}
if (is_string($entityWriteResult->getPrimaryKey())) {
$ids[] = $entityWriteResult->getPrimaryKey();
$mapping[$entityWriteResult->getPrimaryKey()] = $catalogPageId;
}
if (is_array($entityWriteResult->getPrimaryKey())) {
$ids = array_merge($entityWriteResult->getPrimaryKey(), $ids);
foreach ($entityWriteResult->getPrimaryKey() as $id) {
$mapping[$id] = $catalogPageId;
}
}
}
$ids = array_unique($ids);
$upsertCollection = [];
foreach ($ids as $id) {
if (isset($mapping[$id]) && !$mapping[$id] !== null) {
$catalogPageId = $mapping[$id];
} else {
continue; // TODO Get Catalog Page Id;
}
if ($this->checkDotExists($catalogPageId, $id)) {
continue;
}
$upsertCollection[] = [
'id' => Uuid::randomHex(),
'catalogPageId' => $catalogPageId,
'catalogProductId' => $id,
'xPosition' => $this->getXPosition($catalogPageId),
'yPosition' => ProductDotDefinition::DEFAULT_Y,
'enabled' => false,
'hideOnMobile' => false,
'radius' => ProductDotDefinition::DEFAULT_RADIUS,
];
}
if (!empty($upsertCollection)) {
$this->catalogProductDotRepository->upsert($upsertCollection, Context::createDefaultContext());
}
}
private function checkDotExists(string $catalogPageId, string $catalogProductId): bool
{
$this->initCache($catalogPageId);
/** @var ArrayEntity $element */
foreach ($this->dotsCache[$catalogPageId] as $element) {
if ($element['catalogProductId'] === $catalogProductId) {
return true;
}
}
return false;
}
private function initCache(string $catalogPageId): void
{
if (!isset($this->dotsCache[$catalogPageId])) {
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('catalogPageId', $catalogPageId));
$this->dotsCache[$catalogPageId] = $this->catalogProductDotRepository->search($criteria, Context::createDefaultContext())->getElements();
}
}
private function getXPosition(string $catalogPageId): int
{
if (isset($this->positionsCache[$catalogPageId])) {
$this->positionsCache[$catalogPageId] = $this->positionsCache[$catalogPageId] + ProductDotDefinition::DEFAULT_X_STEP;
return $this->positionsCache[$catalogPageId];
}
$this->initCache($catalogPageId);
$currentX = ProductDotDefinition::DEFAULT_X - ProductDotDefinition::DEFAULT_X_STEP;
/** @var ArrayEntity $element */
foreach ($this->dotsCache[$catalogPageId] as $element) {
if ($element['yPosition'] === ProductDotDefinition::DEFAULT_Y && $element['xPosition'] > $currentX) {
$currentX = $element['xPosition'];
}
}
$this->positionsCache[$catalogPageId] = $currentX + ProductDotDefinition::DEFAULT_X_STEP;
return $this->positionsCache[$catalogPageId];
}
}