<?php declare(strict_types=1);
namespace phpSchmied\LastSeenProducts\Subscriber;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockCollection;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotCollection;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\SalesChannel\Struct\CrossSellingStruct;
use Shopware\Core\Content\Product\Aggregate\ProductCrossSelling\ProductCrossSellingEntity;
use Shopware\Core\Content\Product\ProductCollection;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CrossSellingElement;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CrossSellingElementCollection;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Grouping\FieldGrouping;
use Shopware\Core\Framework\Struct\Collection;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\Snippet\SnippetService;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Product\CrossSelling\CrossSellingLoaderResult;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class lastSeenProducts implements EventSubscriberInterface
{
/**
* @var SystemConfigService
*/
private $systemConfigService;
protected $container;
/**
* @var SalesChannelRepositoryInterface
*/
private $productRepository;
/**
* @var SnippetService
*/
private $snippetService;
public function __construct(
Container $container,
SalesChannelRepositoryInterface $entityRepository,
SystemConfigService $systemConfigService,
SnippetService $snippetService
)
{
$this->container = $container;
$this->productRepository = $entityRepository;
$this->systemConfigService = $systemConfigService;
$this->snippetService = $snippetService;
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents()
{
return [
ProductPageLoadedEvent::class => 'onLoadProduct',
];
}
public function onLoadProduct(ProductPageLoadedEvent $event)
{
/**@var $product SalesChannelProductEntity */
$product = $event->getPage()->getProduct();
$session = new Session();
$last_seen_products = $session->get('last_seen_products');
if (is_array($last_seen_products)) {
$snippet = $this->getSnippet($event);
$cross_selling = new CrossSellingElementCollection();
$product_collection = new ProductCollection();
$product_cross_selling_entity = new ProductCrossSellingEntity();
$product_cross_selling_entity->setId(Uuid::randomHex());
$product_cross_selling_entity->setActive(true);
$product_cross_selling_entity->setLimit((int)$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.limit'));
$product_cross_selling_entity->setPosition(1);
$product_cross_selling_entity->setProductId($product->getId());
$product_cross_selling_entity->setType('productList');
$product_cross_selling_entity->setTranslated(['name' => $snippet['phpSchmied.lastseenproducts.headline']]);
$product_cross_selling_entity->setName($snippet['phpSchmied.lastseenproducts.headline']);
$products = $this->getProducts($last_seen_products, 1, (int)$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.limit'), $event);
foreach ($products->getElements() as $cross_sell_product) {
if ($cross_sell_product->getId() !== $product->getId() && !$product_collection->has($cross_sell_product->getId())) {
$show = false;
/**@var $cross_sell_product ProductEntity* */
if(
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.varianten') !== null &&
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.varianten') === true &&
$cross_sell_product->getParentId() !== null
) {
if(!$product_collection->has($cross_sell_product->getParentId())) {
$parent_products = $this->getProducts([$cross_sell_product->getParentId()], 1, (int)$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.limit'), $event);
foreach ($parent_products->getElements() as $parentProduct) {
$cross_sell_product = $parentProduct;
}
} else {
continue;
}
}
if(
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.inactive') !== null &&
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.inactive') === true &&
!$cross_sell_product->getActive()
) {
continue;
}
if(
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.abverkauf') !== null &&
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.abverkauf') === true &&
!$cross_sell_product->getStock()
) {
continue;
}
if (
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.categories') !== null &&
is_array($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.categories')) &&
count($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.categories'))
) {
foreach ($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.categories') as $category_id) {
if (in_array($category_id, $cross_sell_product->getCategoryTree())) {
$show = true;
}
}
} else {
$show = true;
}
/**@var $cross_sell_product ProductEntity* */
if (
$this->systemConfigService->get('phpSchmiedLastSeenProducts.config.disabledCategories') !== null &&
is_array($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.disabledCategories')) &&
count($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.disabledCategories'))
) {
foreach ($this->systemConfigService->get('phpSchmiedLastSeenProducts.config.disabledCategories') as $category_id) {
if (in_array($category_id, $cross_sell_product->getCategoryTree())) {
$show = false;
}
}
}
if ($show) {
$product_collection->add($cross_sell_product);
}
}
}
//Is any crossSelling element in use
if ($event->getPage()->getCmsPage() === null) {
if ($event->getPage()->getCrossSellings() instanceof CrossSellingLoaderResult) {
$cross_selling_element = new \Shopware\Storefront\Page\Product\CrossSelling\CrossSellingElement();
} else {
$cross_selling_element = new CrossSellingElement();
}
} else {
$cross_selling_element = new CrossSellingElement();
}
$cross_selling_element->setProducts($product_collection);
$cross_selling_element->setCrossSelling($product_cross_selling_entity);
$cross_selling->add($cross_selling_element);
$cross_selling_element->setTotal(count($last_seen_products));
//Is any crossSelling element in use
if ($event->getPage()->getCmsPage() !== null) {
foreach ($event->getPage()->getCmsPage()->getSections()->getBlocks() as $block) {
if ($block->getType() === 'cross-selling') {
foreach ($block->getSlots() as $slot) {
$cs = $slot->getData()->getVars();
if(isset($cs['crossSellings']) && $cs['crossSellings'] !== null) {
$cs['crossSellings']->add($cross_selling_element);
} else {
$crossSellingStruct = new CrossSellingStruct();
$csCollection = new CrossSellingElementCollection();
$csCollection->add($cross_selling_element);
$crossSellingStruct->setCrossSellings($csCollection);
$slot->setData($crossSellingStruct);
}
}
}
}
} else {
if (count($product_collection->getElements())) {
$event->getPage()->getCrossSellings()->add($cross_selling_element);
}
}
}
//If is set a slider limit
$tmp_limit = $this->systemConfigService->get('phpSchmiedLastSeenProducts.config.limit');
//validate the limit value
if ($tmp_limit !== null && $tmp_limit !== '' && is_int((int)$tmp_limit) && (int)$tmp_limit >= 0) {
if ((int)$tmp_limit <= 6) {
$limit = (int)$tmp_limit;
} else {
$limit = 6;
}
} else {
$limit = 0;
}
if (!is_array($last_seen_products)) {
$last_seen_products = [];
}
if (!in_array($product->getId(), $last_seen_products)) {
array_unshift($last_seen_products, $product->getId());
}
if (count($last_seen_products) > $limit) {
$last_seen_products = array_splice($last_seen_products, 0, $limit);
}
$session->set('last_seen_products', $last_seen_products);
}
/**
* Loads the product by product id
* @param $products_array null|array
* @param ProductPageLoadedEvent $event
* @param int $limit
* @throws \Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException
*/
private function getProductsBak(?array $products_array, ProductPageLoadedEvent $event)
{
$criteria = new Criteria($products_array);
$criteria->addAssociation('cover');
$criteria->addAssociation('manufaturer');
return $this->productRepository->search($criteria, $event->getSalesChannelContext());
}
/**
* @param $seenProductIds
* @param $minimumItems
* @param $maximumItems
* @param $context
*
* @return \Shopware\Core\Framework\DataAbstractionLayer\EntityCollection
*/
private function getProducts($seenProductIds, $minimumItems, $maximumItems, $event)
{
if (!$seenProductIds) {
return new EntityCollection();
}
if (count($seenProductIds) < $minimumItems) {
return new EntityCollection();
}
$criteria = new Criteria();
$criteria->addAssociation('cover');
$criteria->addAssociation('manufacturer');
$criteria->setLimit($maximumItems);
$criteria->addFilter(new EqualsAnyFilter('id', $seenProductIds));
$criteria->addFilter(
new NotFilter(
NotFilter::CONNECTION_AND,
[new EqualsFilter('displayGroup', null)]
)
);
$criteria->addGroupField(new FieldGrouping('displayGroup'));
$products = $this->productRepository->search($criteria, $event->getSalesChannelContext())->getEntities();
return $products;
}
private function getSnippet(ProductPageLoadedEvent $event)
{
$languageId = $event->getSalesChannelContext()->getSalesChannel()->getLanguageId();
/** @var EntityRepository $languageRepository */
$languageRepository = $this->container->get('language.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('id', $languageId));
$language = $languageRepository->search($criteria, $event->getContext())->first();
/** @var EntityRepository $localeRepository */
$localeRepository = $this->container->get('locale.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('id', $language->getLocaleId()));
$locale = $localeRepository->search($criteria, $event->getContext())->first();
$snippet_sets = $this->snippetService->getSnippetSet(
$event->getSalesChannelContext()->getSalesChannel()->getId(),
$event->getSalesChannelContext()->getSalesChannel()->getLanguageId(),
$locale->getCode(),
$event->getContext()
);
$translator = $this->container->get('translator');
$catalog = $translator->getCatalogue($locale->getCode());
$snippet = $this->snippetService->getStorefrontSnippets(
$catalog,
$snippet_sets->getId()
);
return $snippet;
}
}