<?php
declare(strict_types=1);
namespace ApplifactionPriceMachine\Subscriber;
use ApplifactionPriceMachine\Event\ProductPricesCalculatedEvent;
use ApplifactionPriceMachine\Service\ProductPriceCalculationService;
use Doctrine\DBAL\Connection;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductListingResolvePreviewEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductSubscriber implements EventSubscriberInterface
{
public function __construct(
private ProductPriceCalculationService $productPriceCalculationService,
private Connection $connection
)
{
}
public static function getSubscribedEvents(): array
{
return [
ProductEvents::PRODUCT_WRITTEN_EVENT => 'queueProductPriceCalculation',
ProductPricesCalculatedEvent::class => 'runVariantPriceCalculations',
ProductPageCriteriaEvent::class => 'onProductPageCriteriaEvent',
ProductListingResolvePreviewEvent::class => 'onProductPageCriteriaEvent'
];
}
/**
* Queue main product and all its variants for the price recalculation
*
* @param EntityWrittenEvent $event
* @return void
*/
public function queueProductPriceCalculation(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $entityWriteResult) {
$this->productPriceCalculationService->queueProductPriceCalculation($entityWriteResult->getPrimaryKey());
$productVariantIdSql = "
SELECT
LOWER(HEX(id)) AS product_id
FROM product
WHERE LOWER(HEX(parent_id)) = :parentId
AND LOWER(HEX(version_id)) = :versionId";
$productVariantIdResults = $this->connection->fetchAllAssociative($productVariantIdSql, [
'parentId' => $entityWriteResult->getPrimaryKey(),
'versionId' => Defaults::LIVE_VERSION
]);
foreach ($productVariantIdResults as $productVariantIdResult) {
$this->productPriceCalculationService->queueProductPriceCalculation($productVariantIdResult['product_id']);
}
}
}
/**
* Run variant product price calculations
*
* @param EntityWrittenEvent $event
* @return void
*/
public function runVariantPriceCalculations(ProductPricesCalculatedEvent $productPricesCalculatedEvent): void
{
$productVariantIdSql = "
SELECT
LOWER(HEX(id)) AS product_id
FROM product
WHERE LOWER(HEX(parent_id)) = :parentId
AND LOWER(HEX(version_id)) = :versionId";
$productVariantIdResults = $this->connection->fetchAllAssociative($productVariantIdSql, [
'parentId' => $productPricesCalculatedEvent->getProductId(),
'versionId' => Defaults::LIVE_VERSION
]);
foreach ($productVariantIdResults as $productVariantIdResult) {
$this->productPriceCalculationService->runProductPriceCalculation($productVariantIdResult['product_id'], $productPricesCalculatedEvent->isDryRun());
}
}
/**
* @param ProductPageCriteriaEvent|ProductListingResolvePreviewEvent $event
* @return void
*/
public function onProductPageCriteriaEvent(ProductPageCriteriaEvent|ProductListingResolvePreviewEvent $event)
{
$productCriteria = $event->getCriteria();
$productCriteria->addAssociation('apmTemporaryPrices');
$association = $productCriteria->getAssociation('apmTemporaryPrices');
$now = (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT);
$association->addFilter(
new RangeFilter('validFrom', [RangeFilter::LTE => $now]),
new RangeFilter('validTo', [RangeFilter::GTE => $now])
);
$association->addSorting(new FieldSorting('createdAt', FieldSorting::ASCENDING));
$association->setLimit(1);
}
}