<?php declare(strict_types=1);
namespace NetzhirschPriceOnRequest\Subscriber;
use Exception;
use NetzhirschPriceOnRequest\NetzhirschPriceOnRequest;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionCollection;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotCollection;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Content\Cms\Events\CmsPageLoadedEvent;
use Shopware\Core\Content\Cms\SalesChannel\Struct\BuyBoxStruct;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductBoxStruct;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductListingStruct;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductSliderStruct;
use Shopware\Core\Content\ImportExport\Event\ImportExportBeforeImportRecordEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingsLoadedEvent;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CrossSellingElement;
use Shopware\Core\Content\ProductStream\Service\ProductStreamBuilder;
use Shopware\Core\Content\Rule\RuleEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\Framework\Validation\DataBag\DataBag;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPage;
use Shopware\Storefront\Page\Navigation\NavigationPage;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Shopware\Storefront\Page\Search\SearchPage;
use Shopware\Storefront\Page\Suggest\SuggestPageLoadedEvent;
use Shopware\Storefront\Page\Wishlist\WishlistPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Symfony\Contracts\Translation\TranslatorInterface;
class PageSubscriber implements EventSubscriberInterface
{
/** @var SystemConfigService $systemConfigService */
private $systemConfigService;
/** @var EntityRepository $productRepository */
private $productRepository;
/** @var EntityRepository $cms */
private $cmsRepository;
/** @var ProductStreamBuilder $productStreamBuilder */
private $productStreamBuilder;
/** @var EntityRepository $productStreamRepository */
private $productStreamRepository;
/** @var EntityRepository $priceOnRequest */
private $priceOnRequest;
/** @var array $options */
private $options;
/** @var TranslatorInterface $translator */
private $translator;
public function __construct(
SystemConfigService $systemConfigService,
EntityRepository $productRepository,
EntityRepository $cmsRepository,
EntityRepository $productStreamRepository,
EntityRepository $priceOnRequest,
ProductStreamBuilder $productStreamBuilder,
TranslatorInterface $translator
)
{
$this->systemConfigService = $systemConfigService;
$this->productRepository = $productRepository;
$this->cmsRepository = $cmsRepository;
$this->productStreamBuilder = $productStreamBuilder;
$this->priceOnRequest = $priceOnRequest;
$this->productStreamRepository = $productStreamRepository;
$this->translator = $translator;
}
public static function getSubscribedEvents(): array
{
return [
ProductListingResultEvent::class => 'onProductList',
ProductSearchResultEvent::class => 'onProductList',
ProductPageLoadedEvent::class => 'onProductPageLoaded',
StorefrontRenderEvent::class => 'onStorefrontRender',
SuggestPageLoadedEvent::class => 'onSuggestPageLoaded',
WishlistPageLoadedEvent::class => 'onWishListPageLoaded',
CmsPageLoadedEvent::class => 'onSlider',
ImportExportBeforeImportRecordEvent::class => 'onBeforeImportRow'
];
}
public function onBeforeImportRow(ImportExportBeforeImportRecordEvent $event)
{
$record = $event->getRecord();
if (
!isset($record['priceOnRequest'])
&& !isset($record['priceOnRequest']['id'])
&& !isset($record['priceOnRequest']['active'])
) {
return;
}
$this->priceOnRequest->upsert([
[
'id' => $record['priceOnRequest']['id'],
'active' => $record['priceOnRequest']['active'],
'productId' => $record['id']
]
], $event->getContext());
}
public function onSlider(CmsPageLoadedEvent $event)
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$options = [];
/** @var CmsPageEntity $result */
foreach ($event->getResult() as $result) {
$options = $this->getOptionsBySections(
$result->getSections(),
$options,
$event->getContext(),
$salesChannelId
);
$result->assign($options);
}
}
public function onWishListPageLoaded(WishlistPageLoadedEvent $event)
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$page = $event->getPage();
$wishlist = $page->getWishlist();
$productListing = $wishlist->getProductListing();
$context = $event->getContext();
$optionToAssign = [];
foreach ($productListing->getElements() as $product)
$optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
$page->assign($optionToAssign);
}
public function onSuggestPageLoaded(SuggestPageLoadedEvent $event)
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$page = $event->getPage();
$searchResult = $page->getSearchResult();
$context = $event->getContext();
$optionToAssign = [];
foreach ($searchResult->getEntities() as $product)
$optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
$page->assign($optionToAssign);
}
public function onProductList(ProductListingResultEvent $event)
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$result = $event->getResult();
$context = $event->getContext();
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$optionToAssign = [];
foreach ($result->getEntities() as $product)
$optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
$this->options = $optionToAssign;
}
public function onStorefrontRender(StorefrontRenderEvent $event)
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$this->setEventParameterForModal($event);
$params = $event->getParameters();
if (!isset($params['page']))
return;
$navigationPage = $params['page'];
/** @var NavigationPage $navigationPage */
if (get_class($navigationPage) != NavigationPage::class && get_class($navigationPage) != SearchPage::class)
return;
/** @var OffcanvasCartPage|NavigationPage $offcanvasCartPage */
$offcanvasCartPage = $params['page'];
$options = [];
if (empty($this->options)) {
$varsPage = $offcanvasCartPage->getVars();
if (!isset($varsPage['cmsPage']))
return;
/** @var CmsPageEntity $cmsPage */
$cmsPage = $varsPage['cmsPage'];
$options = $this->getOptionsBySections(
$cmsPage->getSections(),
$options,
$event->getContext(),
$event->getSalesChannelContext()->getSalesChannelId()
);
if (!empty($options))
$offcanvasCartPage->assign($options);
return;
}
$navigationPage->assign($this->options);
}
private function getOptionsBySections(
CmsSectionCollection $sectionCollection,
array $options,
Context $context,
string $salesChannelId
)
{
foreach ($sectionCollection as $section) {
$varsSection = $section->getVars();
if (!isset($varsSection['blocks']))
continue;
$blocks = $varsSection['blocks'];
/** @var CmsBlockEntity $block */
foreach ($blocks as $block) {
$varsBlock = $block->getVars();
if (!isset($varsBlock['slots']))
continue;
/** @var CmsSlotCollection $slots */
$slots = $varsBlock['slots'];
foreach ($slots->getElements() as $element) {
$data = $element->getData();
if (
empty($data)
|| (
get_class($data) != ProductBoxStruct::class
&& get_class($data) != BuyBoxStruct::class
&& get_class($data) != ProductListingStruct::class
&& get_class($data) != ProductSliderStruct::class
)) {
continue;
}
if (get_class($data) == ProductListingStruct::class) {
$listing = $data->getListing();
foreach ($listing->getEntities() as $entity) {
$options = $this->getOptionToAssign(
$context,
$entity,
$salesChannelId,
$options
);
}
} else if (get_class($data) == ProductSliderStruct::class) {
$products = $data->getProducts();
foreach ($products as $product) {
$options = $this->getOptionToAssign(
$context,
$product,
$salesChannelId,
$options
);
}
} else {
$product = $data->getProduct();
$options = $this->getOptionToAssign(
$context,
$product,
$salesChannelId,
$options
);
}
}
}
}
return $options;
}
private function setEventParameterForModal(StorefrontRenderEvent $event)
{
$cmsPage = null;
$params = $event->getParameters();
if (isset($params['cmsPage'])) {
$cmsPage = $params['cmsPage'];
} elseif (isset($params['page'])) {
/** @var NavigationPage $navigationPage */
$navigationPage = $params['page'];
if (get_class($navigationPage) == NavigationPage::class)
$cmsPage = $navigationPage->getCmsPage();
}
if (empty($cmsPage))
return;
/** @var CmsPageEntity $cmsPage */
$title = $cmsPage->getTranslated()['name'] ?? null;
if (empty($title))
return;
$formName = $this->getFormName($event->getSalesChannelContext()->getSalesChannelId());
$formInCmsPage = false;
if ($formName == $title) {
$formInCmsPage = true;
} else {
/** @var CmsSectionEntity $section */
foreach ($cmsPage->getSections() as $section) {
if ($section->getPageId() == $formName) {
$formInCmsPage = true;
}
}
}
if (!$formInCmsPage)
return;
$productNumber = $event->getRequest()->get('productNumber');
$productName = $event->getRequest()->get('productName');
$data = new DataBag();
$comment = $this->translator->trans('netzhirsch-price-on-request.comment', [
'%productName%' => $productName,
'%productNumber%' => $productNumber,
]);
$subject = $this->translator->trans('netzhirsch-price-on-request.subject', [
'%productName%' => $productName,
'%productNumber%' => $productNumber,
]);
$data->set('comment', $comment);
$data->set('subject', $subject);
$event->setParameter('data', $data);
}
/**
* @throws Exception
*/
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$activeForSalesChannel = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
);
if (empty($activeForSalesChannel)){
return;
}
$page = $event->getPage();
$product = $page->getProduct();
$optionToAssign = [];
$context = $event->getContext();
$salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
$optionToAssign['netzhirschPriceOnRequestActive'] = $this->isPriceOnRequestActive($context, $product, $salesChannelId);
$netzhirschPriceOnRequestShowProductPrice = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.showProductPrice', $salesChannelId
);
$optionToAssign['netzhirschPriceOnRequestShowProductPrice'] = $netzhirschPriceOnRequestShowProductPrice;
$netzhirschPriceOnRequestPageId = $this->getFormPageId($context, $salesChannelId);
$optionToAssign['netzhirschPriceOnRequestPageId'] = $netzhirschPriceOnRequestPageId;
$optionToAssign['netzhirschPriceOnRequestCrossSelling'] = [];
/** $page->getCrossSellings() kann null sein, obwohl der getter das nicht erlaubt */
if (!empty($page->getVars()['crossSellings'])) {
/** @var CrossSellingElement $crossSelling */
foreach ($page->getCrossSellings() as $crossSelling) {
foreach ($crossSelling->getProducts() as $productCrossSelling) {
$optionToAssign['netzhirschPriceOnRequestCrossSelling'][$productCrossSelling->getId()]
=
[
'netzhirschPriceOnRequestActive' => $this->isPriceOnRequestActive($context, $productCrossSelling, $salesChannelId),
'netzhirschPriceOnRequestShowProductPrice' => $netzhirschPriceOnRequestShowProductPrice,
'netzhirschPriceOnRequestPageId' => $netzhirschPriceOnRequestPageId,
'productId' => $productCrossSelling->getId()
]
;
}
}
}
$page->assign(
$optionToAssign
);
}
private function isPriceOnRequestActive(Context $context, ProductEntity $product, string $salesChannelId)
{
$active = $this->isPriceOnRequestActiveByProduct($context, $product);
if (!$active)
$active = $this->isPriceOnRequestActiveByStream($context, $salesChannelId, $product);
return $active;
}
private function isPriceOnRequestActiveByProduct(Context $context, ProductEntity $product)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('productNumber', $product->getProductNumber()));
$criteria->addAssociation('priceOnRequest');
$products = $this->productRepository->search($criteria, $context);
if ($products->count() == 0)
return false;
/** @var ProductEntity $productWitExtensions */
$productWitExtensions = $products->first();
/** @var ArrayEntity $arrayEntity */
$arrayEntity = $productWitExtensions->getExtension('priceOnRequest');
if (empty($arrayEntity))
return false;
return $arrayEntity->get('active');
}
private function getFormPageId(Context $context, string $salesChannelId)
{
$equalsFilterField = 'name';
$equalsFilterFieldValue = 'Preis auf Anfrage';
$formId = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.formName', $salesChannelId
);
if (!empty($formId)) {
$equalsFilterField = 'id';
$equalsFilterFieldValue = $formId;
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter($equalsFilterField, $equalsFilterFieldValue));
$cmsPageEntities = $this->cmsRepository->search($criteria, $context);
if ($cmsPageEntities->count() == 0)
return null;
/** @var CmsPageEntity $cmsPageEntity */
$cmsPageEntity = $cmsPageEntities->first();
if (empty($cmsPageEntity))
return null;
return $cmsPageEntity->getId();
}
private function getFormName(string $salesChannelId)
{
$formName = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.formName', $salesChannelId
);
if (empty($formName))
return 'Preis auf Anfrage';
return $formName;
}
private function isPriceOnRequestActiveByStream(Context $context, string $salesChannelId, ProductEntity $product)
{
$streamNameId = $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.streamName', $salesChannelId
);
$equalsFilterField = 'name';
$equalsFilterFieldValue = 'Preis auf Anfrage';
if (!empty($streamNameId)) {
$equalsFilterField = 'id';
$equalsFilterFieldValue = $streamNameId;
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter($equalsFilterField, $equalsFilterFieldValue));
$productStreams = $this->productStreamRepository->search($criteria, $context);
/** @var RuleEntity $productStream */
$productStream = $productStreams->first();
if (empty($productStream))
return false;
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('productNumber', $product->getProductNumber()));
$filters = $this->productStreamBuilder->buildFilters($productStream->getId(), $context);
foreach ($filters as $filter)
$criteria->addFilter($filter);
/** @var ProductEntity $productWitExtensions */
$product = $this->productRepository->search($criteria, $context)->first();
return !empty($product);
}
/**
* @param Context $context
* @param $product
* @param string $salesChannelId
* @param array $optionToAssign
* @return array
*/
private function getOptionToAssign(Context $context, $product, string $salesChannelId, array $optionToAssign): array
{
$optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestActive']
= $this->isPriceOnRequestActive($context, $product, $salesChannelId);
$optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestShowProductPrice']
= $this->systemConfigService->get(
NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.showProductPrice', $salesChannelId
);
$optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestPageId']
= $this->getFormPageId($context, $salesChannelId);
$optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['productId'] = $product->getId();
return $optionToAssign;
}
}