<?php
namespace App\V4\Form\Type\Task;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use App\Form\CustomerConstraints\ConditionShowCustomerConstraintBuilder;
use App\Form\Type\AbstractViewOrderAwareType;
use App\Form\Type\CustomerResource\CustomerFileType;
use App\Form\Type\SubresourceChoicesTrait;
use App\Listing\Transformer\ListingResponseTransformer;
use App\Model\Traits\TimeStampableFormType;
use App\Model\ViewOrder\ViewOrder;
use App\Normalizer\Form\TextAreaTypeNormalizer;
use App\Service\Cache\CacheManager;
use App\Service\Cache\Exception\UnableToSaveKeyException;
use App\V4\Form\Type\ContactConcernedFilterTrait;
use App\V4\Form\Type\ManagedByFilterTrait;
use App\V4\Form\Type\SectionNameFilterTrait;
use App\V4\Form\Type\TaskTypeFilterTrait;
use App\V4\Logger\SentryLogger;
use App\V4\Model\Contact\Contact;
use App\V4\Model\Prospect\Prospect;
use App\V4\Model\Quote\Quote;
use App\V4\Model\Task\Task;
use App\V4\Model\TaskName\TaskName;
use App\V4\Model\TaskType\TaskType as TaskTypeModel;
use App\V4\Model\TaskType\TaskType as TaskTypeV4;
use DateTime;
use Psr\Cache\CacheException;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Security;
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 TaskType extends AbstractViewOrderAwareType
{
use TaskTypeFilterTrait;
use ContactConcernedFilterTrait;
use ManagedByFilterTrait;
use SectionNameFilterTrait;
use TimeStampableFormType;
use SubresourceChoicesTrait {
getEntityChoices as private getEntityChoicesTrait;
}
/**
* @var CollectionDataProviderInterface
*/
private $collectionDataProvider;
/**
* @var ItemDataProviderInterface
*/
private $itemDataProvider;
/**
* @var CacheManager
*/
private $cacheManager;
/**
* @var RouterInterface
*/
private $router;
/**
* @var Security
*/
private $security;
/**
* @var SentryLogger
*/
private $sentryLogger;
/**
* @param CollectionDataProviderInterface $collectionDataProvider
* @param CacheManager $cacheManager
* @param RouterInterface $router
* @param ItemDataProviderInterface $itemDataProvider
* @param Security $security
* @param SentryLogger $sentryLogger
*/
public function __construct(
CollectionDataProviderInterface $collectionDataProvider,
CacheManager $cacheManager,
RouterInterface $router,
ItemDataProviderInterface $itemDataProvider,
Security $security,
SentryLogger $sentryLogger
) {
$this->collectionDataProvider = $collectionDataProvider;
$this->cacheManager = $cacheManager;
$this->router = $router;
$this->itemDataProvider = $itemDataProvider;
$this->security = $security;
$this->sentryLogger = $sentryLogger;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*
* @return void
*
* @throws CacheException
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws ExceptionInterface
* @throws InvalidArgumentException
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @throws UnableToSaveKeyException
* @throws ResourceClassNotSupportedException
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
parent::buildForm($builder, $options);
$task = $builder->getData();
$quote = $options['quoteId'] ? $this->itemDataProvider->getItem(Quote::class, $options['quoteId']) : null;
$user = $this->security->getUser();
$userId = $user->getUserId();
$managedBy = $task instanceof Task && $task->getManagedBy() ? $task->getManagedBy() : $userId;
$name = $task instanceof Task ? $task->getName() : null;
if ($quote instanceof Quote) {
$managedBy = $managedBy ?? $quote->getManagedBy();
$taskNames = $this->getEntityChoices(TaskName::class);
/** @var TaskName $taskName */
foreach ($taskNames as $taskName) {
if ($taskName->isQuoteReminder()) {
$name = $name ?? $taskName->getName().' '.$quote->getQuoteNumber();
break;
}
}
}
$prospect = null;
if ($task instanceof Task) {
if ($task->getProspect() instanceof Prospect) {
$prospect = $task->getProspect();
}
if ($task->getTaskType() instanceof TaskTypeV4) {
$task->getTaskType()->setNormalizeAsIRI(true);
}
foreach ($task->getContacts() as $contact) {
$contact->setNormalizeAsIRI(true);
}
}
if (null === $prospect && $options['prospectId']) {
$prospect = $this->itemDataProvider->getItem(Prospect::class, $options['prospectId']);
}
if (null !== $prospect) {
$prospect->setNormalizeAsIRI(true);
}
$taskTypes = $this->getEntityChoices(TaskTypeModel::class);
$choicesTaskTypes = [];
$taskTypeTimestamped = [];
/** @var TaskTypeModel $taskType */
foreach ($taskTypes as $taskType) {
$choicesTaskTypes[$taskType->getName()] = $taskType;
if ($taskType->isTimestamped()) {
$taskTypeTimestamped[] = $taskType->getId();
}
}
$builder
->add('contacts', ChoiceType::class, [
'label' => 'task_contacts',
'choices' => $prospect instanceof Prospect
? $this->getEntityChoices(Contact::class, ['prospect' => $prospect->getId()])
: [],
'choice_label' => 'name',
'choice_value' => 'id',
'data' => $task ? array_map(function (Contact $contact) {
return $contact->getId();
}, $task->getContacts()->toArray()) : null,
'attr' => [
ListingResponseTransformer::FORM_SORT_KEY => 'contacts.fullname',
],
'multiple' => true,
'required' => false,
])
->add('prospect', ChoiceType::class, [
'choices' => [
$prospect,
],
'choice_value' => 'id',
'required' => false,
'attr' => [
'type' => 'hidden',
'data-hide-from-vieworders' => true,
],
])
->add('name', TextType::class, [
'label' => 'task_object',
'attr' => [
'data-autocomplete' => $this->router->generate('get_task_names'),
'data-field' => 'name',
],
'required' => true,
'data' => $name,
])
->add('beginAt', DateTimeType::class, [
'label' => 'beginAt_task',
'input' => 'datetime',
'widget' => 'single_text',
'html5' => false,
'data' => $task instanceof Task && $task->getBeginAt() instanceof DateTime ? $task->getBeginAt() : new DateTime(),
'format' => "yyyy-MM-dd'T'HH:mm",
])
->add('endAt', DateTimeType::class, [
'input' => 'datetime',
'widget' => 'single_text',
'html5' => false,
'format' => "yyyy-MM-dd'T'HH:mm",
'required' => false,
'attr' => [
ConditionShowCustomerConstraintBuilder::DATA_CONDITION_FIELD => 'taskType',
ConditionShowCustomerConstraintBuilder::DATA_CONDITION_VALUE => $taskTypeTimestamped,
ConditionShowCustomerConstraintBuilder::DATA_CONDITION_IS_VISIBLE => false,
],
])
->add('taskType', ChoiceType::class, [
'choices' => $taskTypes,
'choice_label' => 'name',
'choice_value' => 'id',
'attr' => [
'data-hide-fields' => true,
'data-targets' => 'endAt',
'data-choices-attr' => implode(';', array_map(function (TaskTypeModel $taskType) {
return $taskType->isTimestamped() ? '1' : '0';
}, $choicesTaskTypes)),
ListingResponseTransformer::FORM_SORT_KEY => 'taskType.name',
],
])
->add('managedBy', ChoiceType::class, [
'choices' => $this->getManagedByChoices(),
'required' => true,
'data' => $managedBy,
])
->add('isClosed', CheckboxType::class, [
'false_values' => [null, '0', 0, false, '', 'false'],
'required' => false,
])
->add('memo', TextareaType::class, [
'required' => false,
'attr' => [
TextAreaTypeNormalizer::DATA_ATTR_WYSIWYG_MODE => TextAreaTypeNormalizer::WYSIWYG_MODE_FULL,
],
])
->add('sectionName', ChoiceType::class, [
'choices' => $this->getSectionNameChoices(),
'required' => false,
'attr' => [
'data-hide-from-vieworders' => true,
],
])
->add('report', TextareaType::class, [
'required' => false,
'attr' => [
TextAreaTypeNormalizer::DATA_ATTR_WYSIWYG_MODE => TextAreaTypeNormalizer::WYSIWYG_MODE_FULL,
],
])
->add('customerFiles', CollectionType::class, [
'entry_type' => CustomerFileType::class,
'required' => false,
'allow_add' => true,
'delete_empty' => true,
])
->add('quotes', CollectionType::class, [
'entry_type' => TaskQuoteExternalRefType::class,
'entry_options' => [
'allow_extra_fields' => $options['allow_extra_fields'] ?? false,
],
'required' => false,
'allow_add' => true,
'delete_empty' => true,
'attr' => [
'data-hide-from-vieworders' => true,
'type' => 'hidden',
],
])
->add('nbClic', HiddenType::class, [
'label' => 'nb_clic',
'required' => false,
'mapped' => false,
'attr' => [
ListingResponseTransformer::FORM_SORT_KEY => 'taskMailingStats.nbClic',
],
])
->add('nbRead', HiddenType::class, [
'label' => 'nb_readings',
'required' => false,
'mapped' => false,
'attr' => [
ListingResponseTransformer::FORM_SORT_KEY => 'taskMailingStats.nbReading',
],
])
->add('isDraft', CheckboxType::class, [
'label' => 'task_isDraft',
'false_values' => [null, '0', 0, false, '', 'false'],
'required' => false,
])
;
$builder->get('contacts')->resetViewTransformers();
}
/**
* @param OptionsResolver $resolver
*
* @return void
*/
public function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'data_class' => Task::class,
'csrf_protection' => false,
'prospectId' => null,
'quoteId' => null,
self::FORM_CONFIG_VIEW_ORDER_ENTITY => Task::class,
self::FORM_CONFIG_VIEW_ORDER_TYPE => ViewOrder::VIEWORDER_TYPE_FORM,
self::FORM_CONFIG_SPECIFIC_FIELD_ENTITY => Task::class,
self::FORM_CONFIG_VIEW_ORDER_ENTITY_TYPE => null,
'validation_groups' => function (FormInterface $form) {
$data = $form->getData();
if ($data instanceof Task && $data->getTaskType() instanceof TaskType) {
$taskType = $this->itemDataProvider->getItem(
TaskType::class,
$data->getTaskType()
);
if ($taskType->isTimestamped()) {
return ['Default', 'tasktype_is_timestamped'];
}
}
return ['Default'];
},
]);
}
/**
* @param string $entityFQCN
* @param array $filters
*
* @return array<string, object>
*
* @throws CacheException
* @throws InvalidArgumentException
*/
private function getEntityChoices(string $entityFQCN, array $filters = []): array
{
return $this->getEntityChoicesTrait(
$this->collectionDataProvider,
$this->cacheManager,
$this->sentryLogger,
$entityFQCN,
$filters
);
}
}