<?php
declare(strict_types=1);
namespace Wbfk\ITScope\Subscriber;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\InsertCommand;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\UpdateCommand;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Contracts\Translation\TranslatorInterface;
use Wbfk\ITScope\Core\Content\WbfkSupplier\WbfkSupplierDefinition;
class SupplierDeliveryTimeConfigurationValidator implements EventSubscriberInterface
{
public function __construct(private readonly TranslatorInterface $translator)
{
}
public static function getSubscribedEvents(): array
{
return [
PreWriteValidationEvent::class => 'preValidate',
];
}
public function preValidate(PreWriteValidationEvent $event)
{
return;
$violationList = new ConstraintViolationList();
foreach ($event->getCommands() as $command) {
if (!($command instanceof InsertCommand || $command instanceof UpdateCommand)) {
continue;
}
if ($command->getDefinition()->getClass() !== WbfkSupplierDefinition::class) {
continue;
}
$violationList->addAll($this->validateDeliveryTimeConfigurations($command));
}
if ($violationList->count() > 0) {
$event->getExceptions()->add(new WriteConstraintViolationException($violationList));
}
}
private function validateDeliveryTimeConfigurations(InsertCommand|UpdateCommand $command): ConstraintViolationList
{
$payload = $command->getPayload();
$deliveryTimes = json_decode($payload['delivery_times'], true);
$violationList = new ConstraintViolationList();
$this->validateDefaultConfigurationIsSet($deliveryTimes, $violationList, $command);
$this->validateConfigForEachCountry($deliveryTimes, $violationList, $command);
return $violationList;
}
private function validateDefaultConfigurationIsSet(
array $deliveryTimes,
ConstraintViolationList $violationList,
InsertCommand|UpdateCommand $command
) {
foreach ($deliveryTimes as $deliveryTime) {
if ($deliveryTime['isDefault']) {
// a default config is found, no further check required.
return;
}
}
$message = $this->translator->trans('deliveryTimes.error.requiresDefaultDeliveryTime');
$uuid = $this->getUuid($command);
$violationList->add(
new ConstraintViolation(
$message,
$message,
[],
'',
$command->getPath().'/delivery_times',
null,
null,
$uuid,
)
);
}
public function getUuid(UpdateCommand|InsertCommand $command): string
{
$uuid = bin2hex($command->getPrimaryKey()['id']);
return substr($uuid, 0, 8).'-'.substr($uuid, 8, 4).'-'.substr($uuid, 12, 4).'-'.substr(
$uuid,
16,
4
).'-'.substr($uuid, 20);
}
private function validateConfigForEachCountry(
mixed $deliveryTimes,
ConstraintViolationList $violationList,
UpdateCommand|InsertCommand $command
) {
foreach (
$deliveryTimes as ['isLinked' => $isLinked,
'countryId' => $countryId,
'isDefault' => $isDefault,
'parcelDelivery' => $parcelDelivery,
'freightDelivery' => $freightDelivery]
) {
if ($isLinked) {
continue;
}
$this->validateDeliveryTime($countryId, 'parcelDelivery', $parcelDelivery, $violationList, $command);
$this->validateDeliveryTime($countryId, 'freightDelivery', $freightDelivery, $violationList, $command);
}
}
private function validateDeliveryTime(
string $countryId,
string $deliveryType,
array $deliveryConfig,
ConstraintViolationList $violationList,
InsertCommand|UpdateCommand $command
) {
[
'sameDayShipping' => $sameDayShipping,
'deliveryTimeInDays' => $deliveryTimeInDays,
'shippingTimeInDays' => $shippingTimeInDays,
'sameDayShippingTillTime' => $sameDayShippingTillTime,
] = $deliveryConfig;
if ($sameDayShipping && !$this->validTime($sameDayShippingTillTime)) {
$message = $this->translator->trans('deliveryTimes.error.requiresValidSameDayShippingTillTime');
$violationList->add(
$this->generateDeliveryTimeViolation(
$countryId,
$deliveryType,
$message,
$command
)
);
}
if (!$sameDayShipping && !is_int($shippingTimeInDays) || $shippingTimeInDays < 1) {
$message = $this->translator->trans('deliveryTimes.error.requiresValidShippingTimeInDays');
$violationList->add(
$this->generateDeliveryTimeViolation(
$countryId,
$deliveryType,
$message,
$command
)
);
}
if (!is_int($deliveryTimeInDays) || $deliveryTimeInDays < 1) {
$message = $this->translator->trans('deliveryTimes.error.requiresValidDeliveryTimeInDays');
$violationList->add(
$this->generateDeliveryTimeViolation(
$countryId,
$deliveryType,
$message,
$command
)
);
}
}
private function validTime(?string $time): bool
{
return (bool)preg_match('#^([01]?[0-9]|2[0-3]):[0-5][0-9]$#', (string)$time);
}
private function generateDeliveryTimeViolation(
string $countryId,
string $deliveryType,
string $message,
UpdateCommand|InsertCommand $command
): ConstraintViolation {
return new ConstraintViolation(
$message,
$message,
[],
'',
$command->getPath()."/delivery_times/$countryId/$deliveryType",
null,
null,
$this->getUuid($command)
);
}
}