<?php
namespace App\EventSubscriber;
use App\Form\CustomerConstraints\CustomerConstraintBuilder;
use App\Form\CustomerConstraints\ValueTypeCustomerConstraintBuilder;
use App\Form\Type\AbstractViewOrderAwareType;
use App\Listing\Transformer\ListingResponseTransformer;
use App\Model\ViewOrderInfo\ViewOrderInfo;
use App\Service\ViewOrders\ViewOrdersManager;
use App\V4\Model\Prospect\Prospect;
use Doctrine\Common\Annotations\AnnotationException;
use LogicException;
use ReflectionClass;
use ReflectionException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Event\PreSetDataEvent;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class ViewOrdersAwareFormTypeEventSubscriber implements EventSubscriberInterface
{
/**
* @var ViewOrdersManager
*/
private $viewOrdersManager;
/**
* @var CustomerConstraintBuilder
*/
private $customerConstraintBuilder;
/**
* @param ViewOrdersManager $viewOrdersManager
* @param CustomerConstraintBuilder $customerConstraintBuilder
*/
public function __construct(ViewOrdersManager $viewOrdersManager, CustomerConstraintBuilder $customerConstraintBuilder)
{
$this->viewOrdersManager = $viewOrdersManager;
$this->customerConstraintBuilder = $customerConstraintBuilder;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
FormEvents::PRE_SET_DATA => 'onPreSetData',
];
}
/**
* @param PreSetDataEvent $event
*
* @return bool
*/
public function supports(PreSetDataEvent $event): bool
{
return $event->getForm()->getConfig()->getType()->getInnerType() instanceof AbstractViewOrderAwareType;
}
/**
* @param PreSetDataEvent $event
*
* @return void
*
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ReflectionException
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @throws AnnotationException
* @throws ExceptionInterface
*/
public function onPreSetData(PreSetDataEvent $event): void
{
if (!$this->supports($event)) {
throw new LogicException(sprintf('%s should not be used with %s as it does not extends %s', __CLASS__, get_class($event->getForm()->getConfig()->getType()->getInnerType()), AbstractViewOrderAwareType::class));
}
$entity = $event->getForm()->getConfig()->getOption(AbstractViewOrderAwareType::FORM_CONFIG_VIEW_ORDER_ENTITY);
$type = $event->getForm()->getConfig()->getOption(AbstractViewOrderAwareType::FORM_CONFIG_VIEW_ORDER_TYPE);
$subType = $event->getForm()->getConfig()->getOption(AbstractViewOrderAwareType::FORM_CONFIG_VIEW_ORDER_ENTITY_TYPE);
$rc = new ReflectionClass($entity);
$vo = $this->viewOrdersManager->getViewOrders($rc->getShortName(), $type, $subType);
foreach ($vo as $voGroups) {
foreach ($voGroups->getViewOrderInfos() as $voItem) {
$fieldKey = $voItem->getFieldKey();
if (Prospect::class === $entity) {
if (str_starts_with($fieldKey, 'unmappedAddress_')) {
$fieldKey = str_replace('unmappedAddress_', 'contact_mainAddress_', $fieldKey);
} elseif (str_starts_with($fieldKey, 'deliveryAddress_')) {
$fieldKey = str_replace('deliveryAddress_', 'contact_deliveryAddress_', $fieldKey);
}
}
$form = $this->getFormByFieldKey($event->getForm(), $fieldKey, $voItem);
if (!$form->has($fieldKey)) {
$fieldKeyExploded = explode('_', $fieldKey);
if ($voItem->isSpecificField() && $form->has('sf_'.$fieldKey)) {
$fieldKey = 'sf_'.$fieldKey;
} elseif ($form->has(end($fieldKeyExploded))) {
$fieldKey = end($fieldKeyExploded);
}
}
if (!$form->has($fieldKey)) {
continue;
}
foreach ($this->customerConstraintBuilder->getCustomerConstraints() as $customerConstraint) {
if ($customerConstraint->supports($form, $voItem, $fieldKey, $event->getData())) {
$customerConstraint->build($form, $voItem, $fieldKey);
}
}
$formItem = $form->get($fieldKey);
$type = get_class($formItem->getConfig()->getType()->getInnerType());
$options = array_merge(
$formItem->getConfig()->getOptions(),
[
'label' => $formItem->getConfig()->getOption('label') ?? $voItem->getDisplayLabel(),
]
);
if (ViewOrderInfo::VALUE_TYPE_RICH_TEXT === $voItem->getValueType()) {
$type = TextareaType::class;
$options = array_merge($options, [
'attr' => [
ValueTypeCustomerConstraintBuilder::DATA_SUB_TYPE => ListingResponseTransformer::TYPE_HTML,
'rich-text-editor' => 'rich-rich-editor',
],
]);
}
$form
->remove($fieldKey)
->add(
$fieldKey,
$type,
$options
)
;
}
}
}
/**
* @param FormInterface $form
* @param string|null $fieldKey
* @param ViewOrderInfo $voItem
*
* @return FormInterface
*/
private function getFormByFieldKey(FormInterface $form, ?string $fieldKey, ViewOrderInfo $voItem): FormInterface
{
if ($form->has($fieldKey) || ($voItem->isSpecificField() && $form->has('sf_'.$fieldKey))) {
return $form;
}
$fieldKeyExploded = explode('_', $fieldKey);
foreach ($fieldKeyExploded as $fieldPart) {
if ($form->has($fieldPart) && $fieldPart !== end($fieldKeyExploded)) {
$form = $form->get($fieldPart);
}
}
return $form;
}
}