<?php declare(strict_types=1);
namespace Acris\Filter\Storefront\Subscriber;
use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionEntity;
use Shopware\Core\Content\Property\PropertyEvents;
use Shopware\Core\Content\Property\PropertyGroupEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
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\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PropertyGroupSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private $propertyRepository;
/**
* @var EntityRepositoryInterface
*/
private $optionRepository;
/**
* @var EntityRepositoryInterface
*/
private $languageRepository;
public function __construct(
EntityRepositoryInterface $propertyRepository,
EntityRepositoryInterface $optionRepository,
EntityRepositoryInterface $languageRepository
)
{
$this->propertyRepository = $propertyRepository;
$this->optionRepository = $optionRepository;
$this->languageRepository = $languageRepository;
}
public static function getSubscribedEvents(): array
{
return [
PropertyEvents::PROPERTY_GROUP_WRITTEN_EVENT => [
['updateByPropertyGroup', 2000]
],
PropertyEvents::PROPERTY_GROUP_OPTION_WRITTEN_EVENT => [
['updateByPropertyGroupOption', 2000]
]
];
}
public function updateByPropertyGroup(EntityWrittenEvent $event): void
{
// don't update if only group was updated
if (is_array($event->getPayloads()) && array_key_exists(0, $event->getPayloads()) && empty($event->getPayloads()[0])) {
return;
}
$context = $event->getContext();
$contextExtensions = $context->getExtensions();
if (!empty($contextExtensions) && array_key_exists('acrisFilter', $contextExtensions) && $contextExtensions['acrisFilter']->has('entityUpdated') && ($contextExtensions['acrisFilter']->get('entityUpdated') === true)) {
return;
}
$ids = $event->getIds();
$criteria = new Criteria($ids);
$criteria->addAssociation('options');
/** @var PropertyGroupEntity $property */
$property = $this->propertyRepository->search($criteria, $context)->first();
if (!$property) return;
$updateData = $this->updatePropertyGroupAndOption($property, null, $context);
if (!empty($updateData)) {
$context->addExtension('acrisFilter', new ArrayEntity(['entityUpdated' => true]));
$this->optionRepository->update($updateData, $context);
}
}
public function updateByPropertyGroupOption(EntityWrittenEvent $event): void
{
$context = $event->getContext();
$contextExtensions = $context->getExtensions();
if (!empty($contextExtensions) && array_key_exists('acrisFilter', $contextExtensions) && $contextExtensions['acrisFilter']->has('entityUpdated') && ($contextExtensions['acrisFilter']->get('entityUpdated') === true)) {
return;
}
$ids = $event->getIds();
$criteria = new Criteria($ids);
$criteria->addAssociation('group');
/** @var PropertyGroupOptionEntity $option */
$option = $this->optionRepository->search($criteria, $context)->first();
if (!$option) return;
$updateData = $this->updatePropertyGroupAndOption($option->getGroup(), $option, $context);
if (!empty($updateData)) {
$context->addExtension('acrisFilter', new ArrayEntity(['entityUpdated' => true]));
$this->optionRepository->update($updateData, $context);
}
}
public function updatePropertyGroupAndOption(PropertyGroupEntity $propertyGroupEntity, ?PropertyGroupOptionEntity $propertyGroupOptionEntity, Context $context): array
{
$customFields = $propertyGroupEntity->getTranslation('customFields');
$update = [];
if (!empty($customFields) && array_key_exists('acris_filter_type', $customFields)) {
$filterType = $customFields['acris_filter_type'];
if ($filterType === 'range_min_max' || $filterType === 'range_slider') {
$otherLanguageIds = $this->languageRepository->searchIds((new Criteria())->addFilter(new NotFilter(MultiFilter::CONNECTION_AND, [new EqualsFilter('id', $context->getLanguageId())])), $context)->getIds();
if ($propertyGroupOptionEntity) {
$update = $this->addToUpdateArray($update, $propertyGroupOptionEntity->getId(), $propertyGroupOptionEntity->getTranslation('customFields'), $propertyGroupOptionEntity->getTranslation('name'), $otherLanguageIds);
} else {
foreach ($propertyGroupEntity->getOptions() as $propertyGroupOptionEntity) {
$update = $this->addToUpdateArray($update, $propertyGroupOptionEntity->getId(), $propertyGroupOptionEntity->getTranslation('customFields'), $propertyGroupOptionEntity->getTranslation('name'), $otherLanguageIds);
}
}
}
}
return $update;
}
private function addToUpdateArray(array $update, string $id, ?array $customFields, ?string $name, ?array $otherLanguageIds): array
{
$updateCustomFields = [];
$numericValue = null;
if (str_contains($name, ",")) {
$val = str_replace(",", ".", $name);
if (substr_count($val, ".") > 1) {
$numericValue = (double)preg_replace('/\.(?=.*\.)/', '', $val);
} else {
$numericValue = (double)$val;
}
} elseif (substr_count($name, ".") > 1) {
$numericValue = (double)preg_replace('/\.(?=.*\.)/', '', $name);
} else {
$numericValue = (double)$name;
}
if (empty($customFields) || (array_key_exists('acris_filter_numeric', $customFields) && floatval($customFields['acris_filter_numeric']) !== $numericValue)) {
$updateCustomFields['acris_filter_numeric'] = $numericValue;
$translations = [];
foreach ($otherLanguageIds as $otherLanguageId) {
$translations[] = ['languageId' => $otherLanguageId, 'customFields' => $updateCustomFields];
}
if (!empty($translations)) {
$update[] = ['id' => $id, 'customFields' => $updateCustomFields, 'translations' => $translations];
} else {
$update[] = ['id' => $id, 'customFields' => $updateCustomFields];
}
}
return $update;
}
}