<?php
declare(strict_types=1);
namespace LinkMobility\ShopwareSmsApiPlugin\Subscriber;
use LinkMobility\ShopwareSmsApiPlugin\Core\Content\Entity\BackInStockReminder\BackInStockReminderEntity;
use LinkMobility\ShopwareSmsApiPlugin\Factory\SmsConfigFactoryInterface;
use LinkMobility\ShopwareSmsApiPlugin\Service\SmsSenderInterface;
use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Content\Product\ProductEvents;
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\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\ChangeSetAware;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductPageSubscriber implements EventSubscriberInterface
{
public function __construct(
private SystemConfigService $configService,
private EntityRepository $backInStockRemindRepository,
private SmsSenderInterface $smsSender,
private SmsConfigFactoryInterface $smsConfigFactory,
) {
}
public static function getSubscribedEvents(): array
{
return [
ProductEvents::PRODUCT_WRITTEN_EVENT => 'notifyCustomers',
PreWriteValidationEvent::class => 'triggerChangeSet',
ProductPageLoadedEvent::class => 'onProductPageLoaded',
];
}
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$context = $event->getPage();
$config = $this->configService->get('LinkMobilityShopwareSmsApiPlugin.productAware');
$restockNotifier = $config['restockNotifier'] ?? false;
if ($restockNotifier) {
$context->addExtension('smsNotifier', new ArrayEntity(['on' => true]));
}
}
public function notifyCustomers(EntityWrittenEvent $event): void
{
$productsWritten = $event->getWriteResults();
$restockNotifier = $this->smsConfigFactory->createRestockNotifierConfig();
if (!$restockNotifier->isActive()) {
return;
}
foreach ($productsWritten as $productWritten) {
if (!$this->isBackInStock($productWritten)) {
continue;
}
$payload = $productWritten->getPayload();
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('productId', $payload['id']));
$criteria->addAssociation('product');
$context = $event->getContext();
$reminderEntities = $this->backInStockRemindRepository->search($criteria, $context)->getEntities();
/** @var BackInStockReminderEntity $reminderEntity */
foreach ($reminderEntities as $reminderEntity) {
$product = $reminderEntity->getProduct();
if (null === $product) {
continue;
}
$this->smsSender->sendProductAware($product, $reminderEntity->getPhoneNumber(), $restockNotifier->getMessage());
$this->backInStockRemindRepository->delete([[
'id' => $reminderEntity->getId(),
]], $context);
}
}
}
public function triggerChangeSet(PreWriteValidationEvent $event): void
{
foreach ($event->getCommands() as $command) {
if (!$command instanceof ChangeSetAware ||
ProductDefinition::ENTITY_NAME !== $command->getDefinition()->getEntityName()) {
continue;
}
$payload = $command->getPayload();
if (!isset($payload['is_closeout']) &&
!isset($payload['stock'])) {
continue;
}
$command->requestChangeSet();
}
}
private function isBackInStock(EntityWriteResult $productWritten): bool
{
$payload = $productWritten->getPayload();
if ((!isset($payload['isCloseout']) && !isset($payload['stock'])) ||
'0' !== $productWritten->getChangeSet()?->getBefore('available')) {
return false;
}
$stockPayload = $payload['stock'] ?? null;
$isCloseOutPayload = $payload['isCloseout'] ?? false;
if (0 < $stockPayload && $isCloseOutPayload) {
return false;
}
return true;
}
}