<?php declare(strict_types=1);
/**
* (c) 2Hats Logic Solutions <info@2hatslogic.com>
*/
namespace Hatslogic\Sw\ProductsAndLayoutsScheduler\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Doctrine\DBAL\Connection;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\ProductEvents;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Shopware\Core\PlatformRequest;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Hatslogic\Sw\ProductsAndLayoutsScheduler\HatslogicSwProductsAndLayoutsScheduler;
use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
class ProductScheduler implements EventSubscriberInterface
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var Connection
*/
private $connection;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var RouterInterface
*/
private $router;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var EntityRepositoryInterface
*/
private $productRepository;
public function __construct(
ContainerInterface $container,
Connection $connection,
RequestStack $requestStack,
RouterInterface $router,
SystemConfigService $systemConfigService,
EntityRepositoryInterface $productRepository
) {
$this->container = $container;
$this->connection = $connection;
$this->requestStack = $requestStack;
$this->router = $router;
$this->systemConfigService = $systemConfigService;
$this->productRepository = $productRepository;
}
public static function getSubscribedEvents(): array
{
return [
ProductEvents::PRODUCT_LISTING_CRITERIA => 'productListingCriteria',
ProductEvents::PRODUCT_SEARCH_CRITERIA => 'productSearchCriteria',
ProductEvents::PRODUCT_SUGGEST_CRITERIA => 'productSuggestCriteria',
KernelEvents::REQUEST => 'onProductLoaded'
];
}
public function getProductDetailsById($id)
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter(
'product.id', $id));
$result = $this->productRepository->search($criteria, Context::createDefaultContext());
$productDetails = $result->first();
return ($productDetails) ? $productDetails: null;
}
public function onProductLoaded(RequestEvent $event)
{
$request = $event->getRequest();
$attributes = $request->attributes;
$route = $attributes->get('_route');
if($route == 'frontend.detail.page')
{
$productId = $attributes->get('productId');
$salesChannelId = $attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID);
if($this->isProductSchedulerActive($salesChannelId))
{
$productDetails = $this->getProductDetailsById($productId);
if(empty($productDetails)) {
return;
}
$customFields = $productDetails->getCustomFields();
if(!empty($customFields))
{
$productDetailPageVisibilityStatus = $this->getProductDetailPageVisibilityStatus($customFields);
if(!$productDetailPageVisibilityStatus)
{
$response = new RedirectResponse($this->router->generate('frontend.home.page'), 301);
$event->setResponse($response);
return;
}
}
}
}
return;
}
public function getProductDetailPageVisibilityStatus($customFields)
{
$pageVisible = true;
if(!empty($customFields))
{
$currentDateTimeTimeStamp = strtotime(date(HatslogicSwProductsAndLayoutsScheduler::SCHEDULER_DATE_TIME_FORMAT));
$scheduledFrom = isset($customFields['product_scheduled_from']) ? $customFields['product_scheduled_from'] : '';
$scheduledTo = isset($customFields['product_scheduled_to']) ? $customFields['product_scheduled_to'] : '';
$scheduledFromTimeStamp = !empty($scheduledFrom) ? strtotime($scheduledFrom) : '';
$scheduledToTimeStamp = !empty($scheduledTo) ? strtotime($scheduledTo) : '';
if(!empty($scheduledFrom) || !empty($scheduledTo))
{
$pageVisible = false;
}
if(!empty($scheduledFrom) && !empty($scheduledTo))
{
if(($scheduledFromTimeStamp <= $currentDateTimeTimeStamp) && ($scheduledToTimeStamp >= $currentDateTimeTimeStamp))
{
$pageVisible = true;
}
} else if(!empty($scheduledFrom)) {
if($scheduledFromTimeStamp <= $currentDateTimeTimeStamp)
{
$pageVisible = true;
}
} else if(!empty($scheduledTo)) {
if($scheduledToTimeStamp >= $currentDateTimeTimeStamp)
{
$pageVisible = true;
}
}
}
return $pageVisible;
}
public function productSuggestCriteria(ProductSuggestCriteriaEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
if($this->isProductSchedulerActive($salesChannelId))
{
$event->getCriteria()->addAssociation('customFields');
$productScheduledDateRangeFilter = $this->getProductScheduledDateRangeFilter();
$event->getCriteria()->addFilter(
$productScheduledDateRangeFilter
);
}
return true;
}
public function productSearchCriteria(ProductSearchCriteriaEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
if($this->isProductSchedulerActive($salesChannelId))
{
$event->getCriteria()->addAssociation('customFields');
$productScheduledDateRangeFilter = $this->getProductScheduledDateRangeFilter();
$event->getCriteria()->addFilter(
$productScheduledDateRangeFilter
);
}
return true;
}
public function productListingCriteria(ProductListingCriteriaEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
if($this->isProductSchedulerActive($salesChannelId))
{
$event->getCriteria()->addAssociation('customFields');
$productScheduledDateRangeFilter = $this->getProductScheduledDateRangeFilter();
$event->getCriteria()->addFilter(
$productScheduledDateRangeFilter
);
}
return true;
}
public function getProductScheduledDateRangeFilter(): MultiFilter
{
$filterNoDateRange = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('customFields.product_scheduled_from', null),
new EqualsFilter('customFields.product_scheduled_to', null),
]
);
$filterStartedNoEndDate = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new RangeFilter('customFields.product_scheduled_from', [RangeFilter::LTE => date(HatslogicSwProductsAndLayoutsScheduler::SCHEDULER_DATE_TIME_FORMAT)]),
new EqualsFilter('customFields.product_scheduled_to', null),
]
);
$filterActiveNoStartDate = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('customFields.product_scheduled_from', null),
new RangeFilter('customFields.product_scheduled_to', [RangeFilter::GTE => date(HatslogicSwProductsAndLayoutsScheduler::SCHEDULER_DATE_TIME_FORMAT)]),
]
);
$activeDateRangeFilter = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new RangeFilter('customFields.product_scheduled_from', [RangeFilter::LTE => date(HatslogicSwProductsAndLayoutsScheduler::SCHEDULER_DATE_TIME_FORMAT)]),
new RangeFilter('customFields.product_scheduled_to', [RangeFilter::GTE => date(HatslogicSwProductsAndLayoutsScheduler::SCHEDULER_DATE_TIME_FORMAT)]),
]
);
$dateFilter = new MultiFilter(
MultiFilter::CONNECTION_OR,
[
$filterNoDateRange,
$filterActiveNoStartDate,
$filterStartedNoEndDate,
$activeDateRangeFilter,
]
);
return $dateFilter;
}
public function isProductSchedulerActive($salesChannelId)
{
$isProductSchedulerActive = $this->systemConfigService->get('HatslogicSwProductsAndLayoutsScheduler.config.enableProductsScheduler', $salesChannelId);
return $isProductSchedulerActive;
}
}