<?php declare(strict_types=1);
namespace Shopware\Core\Checkout\Customer\Subscriber;
use Cocur\Slugify\SlugifyInterface;
use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroup\CustomerGroupCollection;
use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroupTranslation\CustomerGroupTranslationCollection;
use Shopware\Core\Content\Seo\SeoUrlPersister;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\Language\LanguageEntity;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CustomerGroupSubscriber implements EventSubscriberInterface
{
private const ROUTE_NAME = 'frontend.account.customer-group-registration.page';
private EntityRepositoryInterface $customerGroupRepository;
private SeoUrlPersister $persister;
private SlugifyInterface $slugify;
private EntityRepositoryInterface $seoUrlRepository;
private EntityRepositoryInterface $languageRepository;
/**
* @internal
*/
public function __construct(
EntityRepositoryInterface $customerGroupRepository,
EntityRepositoryInterface $seoUrlRepository,
EntityRepositoryInterface $languageRepository,
SeoUrlPersister $persister,
SlugifyInterface $slugify
) {
$this->customerGroupRepository = $customerGroupRepository;
$this->seoUrlRepository = $seoUrlRepository;
$this->persister = $persister;
$this->slugify = $slugify;
$this->languageRepository = $languageRepository;
}
public static function getSubscribedEvents(): array
{
return [
'customer_group_translation.written' => 'updatedCustomerGroup',
'customer_group_registration_sales_channels.written' => 'newSalesChannelAddedToCustomerGroup',
'customer_group_translation.deleted' => 'deleteCustomerGroup',
];
}
public function newSalesChannelAddedToCustomerGroup(EntityWrittenEvent $event): void
{
$ids = [];
foreach ($event->getWriteResults() as $writeResult) {
$ids[] = $writeResult->getPrimaryKey()['customerGroupId'];
}
if (\count($ids) === 0) {
return;
}
$this->createUrls($ids, $event->getContext());
}
public function updatedCustomerGroup(EntityWrittenEvent $event): void
{
$ids = [];
foreach ($event->getWriteResults() as $writeResult) {
if ($writeResult->hasPayload('registrationTitle')) {
$ids[] = $writeResult->getPrimaryKey()['customerGroupId'];
}
}
if (\count($ids) === 0) {
return;
}
$this->createUrls($ids, $event->getContext());
}
public function deleteCustomerGroup(EntityDeletedEvent $event): void
{
$ids = [];
foreach ($event->getWriteResults() as $writeResult) {
$ids[] = $writeResult->getPrimaryKey()['customerGroupId'];
}
if (\count($ids) === 0) {
return;
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsAnyFilter('foreignKey', $ids));
$criteria->addFilter(new EqualsFilter('routeName', self::ROUTE_NAME));
/** @var array<string> $ids */
$ids = array_values($this->seoUrlRepository->searchIds($criteria, $event->getContext())->getIds());
if (\count($ids) === 0) {
return;
}
$this->seoUrlRepository->delete(array_map(function (string $id) {
return ['id' => $id];
}, $ids), $event->getContext());
}
private function createUrls(array $ids, Context $context): void
{
$criteria = new Criteria($ids);
$criteria->addFilter(new EqualsFilter('registrationActive', true));
$criteria->addAssociation('registrationSalesChannels.languages');
$criteria->addAssociation('translations');
/** @var CustomerGroupCollection $groups */
$groups = $this->customerGroupRepository->search($criteria, $context)->getEntities();
$buildUrls = [];
foreach ($groups as $group) {
if ($group->getRegistrationSalesChannels() === null) {
continue;
}
foreach ($group->getRegistrationSalesChannels() as $registrationSalesChannel) {
if ($registrationSalesChannel->getLanguages() === null) {
continue;
}
/** @var array<string> $languageIds */
$languageIds = $registrationSalesChannel->getLanguages()->getIds();
$criteria = new Criteria($languageIds);
$languageCollection = $this->languageRepository->search($criteria, $context)->getEntities();
foreach ($languageIds as $languageId) {
$title = $this->getTranslatedTitle($group->getTranslations(), $languageCollection->get($languageId));
if (!isset($buildUrls[$languageId])) {
$buildUrls[$languageId] = [
'urls' => [],
'salesChannel' => $registrationSalesChannel,
];
}
$buildUrls[$languageId]['urls'][] = [
'salesChannelId' => $registrationSalesChannel->getId(),
'foreignKey' => $group->getId(),
'routeName' => self::ROUTE_NAME,
'pathInfo' => '/customer-group-registration/' . $group->getId(),
'isCanonical' => true,
'seoPathInfo' => '/' . $this->slugify->slugify($title),
];
}
}
}
foreach ($buildUrls as $languageId => $config) {
$context = new Context(
$context->getSource(),
$context->getRuleIds(),
$context->getCurrencyId(),
[$languageId]
);
$this->persister->updateSeoUrls(
$context,
self::ROUTE_NAME,
array_column($config['urls'], 'foreignKey'),
$config['urls'],
$config['salesChannel']
);
}
}
private function getTranslatedTitle(?CustomerGroupTranslationCollection $translations, LanguageEntity $language): string
{
if ($translations === null) {
return '';
}
// Requested translation
foreach ($translations as $translation) {
if ($translation->getLanguageId() === $language->getId() && $translation->getRegistrationTitle() !== null) {
return $translation->getRegistrationTitle();
}
}
// Inherited translation
foreach ($translations as $translation) {
if ($translation->getLanguageId() === $language->getParentId() && $translation->getRegistrationTitle() !== null) {
return $translation->getRegistrationTitle();
}
}
// System Language
foreach ($translations as $translation) {
if ($translation->getLanguageId() === Defaults::LANGUAGE_SYSTEM && $translation->getRegistrationTitle() !== null) {
return $translation->getRegistrationTitle();
}
}
return '';
}
}