<?php declare(strict_types=1);
namespace NetInventors\NetiNextStoreLocator\Decorator;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Write\CloneBehavior;
use Shopware\Core\Framework\Uuid\Uuid;
class EntityRepositoryDecorator implements EntityRepositoryInterface
{
private const COUNTRY_ISOS = [
'2' => 'DE',
'3' => 'AE',
'4' => 'AU',
'5' => 'BE',
'7' => 'DK',
'8' => 'FI',
'9' => 'FR',
'10' => 'GR',
'11' => 'GB',
'12' => 'IE',
'13' => 'IS',
'14' => 'IT',
'15' => 'JP',
'16' => 'CA',
'18' => 'LU',
'20' => 'NA',
'21' => 'NL',
'22' => 'NO',
'23' => 'AT',
'24' => 'PT',
'25' => 'SE',
'26' => 'CH',
'27' => 'ES',
'28' => 'US',
'29' => 'LI',
'30' => 'PL',
'31' => 'HU',
'32' => 'TR',
'33' => 'CZ',
'34' => 'SK',
'35' => 'RO',
'36' => 'BR',
'37' => 'IL',
];
/**
* @var EntityRepositoryInterface
*/
private $repository;
/**
* @var EntityRepositoryInterface
*/
private $salesChannelRepository;
/**
* @var EntityRepositoryInterface
*/
private $countryRepository;
/**
* @var EntityRepositoryInterface
*/
private $countryStateRepository;
/**
* EntityRepositoryDecorator constructor.
*
* @param EntityRepositoryInterface $repository
* @param EntityRepositoryInterface $salesChannelRepository
* @param EntityRepositoryInterface $countryRepository
* @param EntityRepositoryInterface $countryStateRepository
*/
public function __construct(
EntityRepositoryInterface $repository,
EntityRepositoryInterface $salesChannelRepository,
EntityRepositoryInterface $countryRepository,
EntityRepositoryInterface $countryStateRepository
) {
$this->repository = $repository;
$this->salesChannelRepository = $salesChannelRepository;
$this->countryRepository = $countryRepository;
$this->countryStateRepository = $countryStateRepository;
}
public function getDefinition(): EntityDefinition
{
return $this->repository->getDefinition();
}
public function aggregate(Criteria $criteria, Context $context): AggregationResultCollection
{
return $this->repository->aggregate($criteria, $context);
}
public function searchIds(Criteria $criteria, Context $context): IdSearchResult
{
return $this->repository->searchIds($criteria, $context);
}
public function clone(string $id, Context $context, ?string $newId = null, ?CloneBehavior $behavior = null): EntityWrittenContainerEvent
{
return $this->repository->clone($id, $context, $newId, $behavior);
}
public function search(Criteria $criteria, Context $context): EntitySearchResult
{
return $this->repository->search($criteria, $context);
}
public function update(array $data, Context $context): EntityWrittenContainerEvent
{
return $this->repository->update($data, $context);
}
public function upsert(array $data, Context $context): EntityWrittenContainerEvent
{
if (!array_key_exists('excludeFromSync', $data[0]) && array_key_exists('label', $data[0])) {
$data[0]['countryId'] = $this->getCountryId($data[0]['countryId'], $context);
$data[0]['id'] = $this->createStoreId($data[0], $context);
/**
* Due to the condition above data must be an array
*
* @psalm-suppress MixedArgument
*/
$data[0]['showAlways'] = $this->setShowAlways($data[0]);
$salesChannelIds = $this->getSalesChannelsIds($context);
unset($data[0]['salesChannels']);
foreach ($salesChannelIds as $channelId) {
$data[0]['salesChannels'][] = [ 'id' => $channelId ];
}
}
if (isset($data[0]['salesChannels'])) {
$data[0]['salesChannels'] = $this->assignSalesChannel($data[0]['salesChannels'], $context);
}
if (isset($data[0]['countryId'])) {
$data[0]['countryId'] = $this->assignCountryIdByIso($data[0], $context);
if (isset($data[0]['country'])) {
unset($data[0]['country']);
}
if (isset($data[0]['countryState'])) {
$data[0]['countryStateId'] = $this->assignCountryStateByShortCode($data[0], $context);
unset($data[0]['countryState']);
}
}
return $this->repository->upsert($data, $context);
}
public function create(array $data, Context $context): EntityWrittenContainerEvent
{
return $this->repository->create($data, $context);
}
public function delete(array $data, Context $context): EntityWrittenContainerEvent
{
return $this->repository->delete($data, $context);
}
public function createVersion(string $id, Context $context, ?string $name = null, ?string $versionId = null): string
{
return $this->repository->createVersion($id, $context, $name, $versionId);
}
public function merge(string $versionId, Context $context): void
{
$this->repository->merge($versionId, $context);
}
private function getSalesChannelsIds(Context $context): array
{
$criteria = new Criteria();
return $this->salesChannelRepository->searchIds($criteria, $context)->getIds();
}
/**
* @param string $id
* @param Context $context
*
* @return string
*/
private function getCountryId(string $id, Context $context): string
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('iso', self::COUNTRY_ISOS[$id] ?? 'DE'));
return $this->countryRepository->searchIds($criteria, $context)->firstId();
}
/**
* @param array $data
* @param Context $context
*
* @return string
*/
private function createStoreId(array $data, Context $context): string
{
unset($data['salesChannels'], $data['id']);
$criteria = new Criteria();
foreach ($data as $key => $value) {
if ($key !== 'country' && !empty($value)) {
$criteria->addFilter(new EqualsFilter($key, $value));
}
}
$result = $this->repository->searchIds($criteria, $context)->firstId();
if (null === $result) {
$result = Uuid::randomHex();
}
return $result;
}
/**
* @param array $data
*
* @return string
*/
private function setShowAlways(array $data): string
{
$newDisplay = 'no';
if (!isset($data['showAlways'])) {
return $newDisplay;
}
$showAlways = (string) $data['showAlways'];
switch ($showAlways) {
case '0':
break;
case '1':
$newDisplay = 'top';
break;
case '2':
$newDisplay = 'bottom';
break;
}
return $newDisplay;
}
/**
* @param string $salesChannelId
* @param Context $context
*
* @return bool
*/
private function isMatchingSalesChannel(string $salesChannelId, Context $context): bool
{
$criteria = new Criteria([ $salesChannelId ]);
$result = $this->salesChannelRepository->searchIds($criteria, $context)->getIds();
return !empty($result);
}
/**
* @param array $salesChannels
* @param Context $context
*
* @return array
*/
private function assignSalesChannel(array $salesChannels, Context $context): array
{
foreach ($salesChannels as $key => $salesChannel) {
if (!$this->isMatchingSalesChannel($salesChannel['id'], $context)) {
unset($salesChannels[$key]);
}
}
if (empty($salesChannels)) {
$defaultSalesChannelIds = $this->getSalesChannelsIds($context);
foreach ($defaultSalesChannelIds as $defaultSalesChannelId) {
$salesChannels[] = [ 'id' => $defaultSalesChannelId ];
}
}
return $salesChannels;
}
/**
* @param array $data
* @param Context $context
*
* @return string
*/
private function assignCountryIdByIso(array $data, Context $context): string
{
if (isset($data['countryId'], $data['country']['iso']) && !$this->isMatchingCountryId($data['countryId'], $context)) {
$data['countryId'] = $this->getCountryByIso($data['country']['iso'], $context);
}
if (!isset($data['countryId']) || null === $data['countryId']) {
$data['countryId'] = $this->getCountryId('deutsch', $context);
}
return $data['countryId'];
}
/**
* @param array $data
* @param Context $context
*
* @return string
*/
private function assignCountryStateByShortCode(array $data, Context $context): string
{
if (isset($data['countryStateId'], $data['countryState']['shortCode']) && !$this->isMatchingCountryStateId($data['countryStateId'], $context)) {
$data['countryStateId'] = $this->getCountryStateByShortCode($data['countryState']['shortCode'], $context);
}
return $data['countryStateId'];
}
/**
* @param string $countryId
* @param Context $context
*
* @return bool
*/
private function isMatchingCountryId(string $countryId, Context $context): bool
{
$criteria = new Criteria([ $countryId ]);
$result = $this->countryRepository->searchIds($criteria, $context)->getIds();
return !empty($result);
}
/**
* @param string $iso
* @param Context $context
*
* @return string|null
*/
private function getCountryByIso(string $iso, Context $context): ?string
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('iso', $iso));
return $this->countryRepository->searchIds($criteria, $context)->firstId();
}
/**
* @param string $countryStateId
* @param Context $context
*
* @return bool
*/
private function isMatchingCountryStateId(string $countryStateId, Context $context): bool
{
$criteria = new Criteria([ $countryStateId]);
$result = $this->countryStateRepository->searchIds($criteria, $context)->getIds();
return !empty($result);
}
/**
* @param string $shortCode
* @param Context $context
*
* @return string|null
*/
private function getCountryStateByShortCode(string $shortCode, Context $context): ?string
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('shortCode', $shortCode));
return $this->countryStateRepository->searchIds($criteria, $context)->firstId();
}
}