<?php
namespace App\Listing\Transformer;
use App\Export\Builder\ExportBuilderInterface;
use App\Export\Builder\ExporterInterface;
use App\Export\ContactConcernedExporter;
use App\Form\Type\CustomerResource\CustomerFileType;
use App\Listing\Builder\HeaderEntryBuilder;
use App\Listing\Builder\ResultEntryBuilder;
use App\Transformer\EntityToFormTypeTransformer;
use App\V4\Controller\AbstractGetSubListAction;
use App\V4\DataProvider\CustomAction\ActionBuilder;
use App\V4\Exporter\LongtextExporter;
use App\V4\Form\FormFieldExtractor;
use App\V4\Model\Contact\Contact;
use App\V4\Model\Prospect\Prospect;
use App\V4\Model\Quote\Quote;
use App\V4\Model\Response\Listing\FieldEntry;
use App\V4\Model\Response\Listing\HeaderEntry;
use App\V4\Model\Response\Listing\ListingResponse;
use App\V4\Model\Task\Task;
use App\ViewOrders\Builder\ViewOrdersBuilder;
use App\ViewOrders\Builder\ViewOrdersBuilderInterface;
use App\ViewOrders\Model\Item;
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\DateType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class ListingResponseTransformer implements ListingResponseTransformerInterface
{
public const FORM_SORT_KEY = 'sortKey';
public const FORM_FILTER_KEY = 'filterKey';
public const KEY_NOT_FOUND = 'KEY_NOT_FOUND';
public const TYPE_TEL = 'TelType';
public const TYPE_MONEY = 'money';
public const TYPE_PERCENT = 'percent';
public const TYPE_EMAIL = 'email';
public const TYPE_LONGTEXT = 'longtext';
public const TYPE_FILES = 'files';
public const TYPE_HTML = 'html';
const LONGTEXT_LENGTH_MAX = 100;
/**
* @var NormalizerInterface
*/
private $normalizer;
/**
* @var ViewOrdersBuilder
*/
private $viewOrdersBuilder;
/**
* @var ExportBuilderInterface
*/
private $exportBuilder;
/**
* @var FormFactoryInterface
*/
private $formFactory;
/**
* @var HeaderEntryBuilder
*/
private $headerEntryBuilder;
/**
* @var ResultEntryBuilder
*/
private $resultEntryBuilder;
/**
* @var ActionBuilder
*/
private $actionBuilder;
/**
* @var FormFieldExtractor
*/
private $formFieldExtractor;
public function __construct(
NormalizerInterface $normalizer,
ViewOrdersBuilder $viewOrdersBuilder,
ExportBuilderInterface $exportBuilder,
FormFactoryInterface $formFactory,
HeaderEntryBuilder $headerEntryBuilder,
ResultEntryBuilder $resultEntryBuilder,
ActionBuilder $actionBuilder,
FormFieldExtractor $formFieldExtractor
) {
$this->normalizer = $normalizer;
$this->viewOrdersBuilder = $viewOrdersBuilder;
$this->exportBuilder = $exportBuilder;
$this->formFactory = $formFactory;
$this->headerEntryBuilder = $headerEntryBuilder;
$this->resultEntryBuilder = $resultEntryBuilder;
$this->actionBuilder = $actionBuilder;
$this->formFieldExtractor = $formFieldExtractor;
}
/**
* @param string $entityFQCN
* @param array $entities
* @param array $context
*
* @return array
*
* @throws ExceptionInterface
*/
public function transform(string $entityFQCN, array $entities, array $context = []): array
{
$replacementResponse = new ListingResponse();
$isSubResource = $context[AbstractGetSubListAction::CONTEXT_IS_SUB_RESOURCE_KEY] ?? false;
$needToAddProspectFullname = in_array($entityFQCN, [Prospect::class, Quote::class, Task::class, Contact::class], true)
&& !$isSubResource
;
if ($needToAddProspectFullname) {
switch ($entityFQCN) {
case Contact::class:
$entityFieldFullname = 'prospect.fullname';
break;
case Task::class:
$entityFieldFullname = 'customerName';
break;
case Quote::class:
$entityFieldFullname = 'prospectFullName';
break;
default:
$entityFieldFullname = 'fullname';
break;
}
$replacementResponse->addHeader(
(new HeaderEntry())
->setKey($entityFieldFullname)
->setLabel('prospect_list_fullname')
->setSortKey($entityFieldFullname)
->addMetadata('type', 'string')
->addMetadata(HeaderEntry::KEY_SORT_TYPE, HeaderEntry::VALUE_SORT_TYPE_ALPHABETICAL)
);
}
$form = $this->formFactory->create((new EntityToFormTypeTransformer())->transform($entityFQCN));
$viewOrders = $this->viewOrdersBuilder->getViewOrder($entityFQCN, ViewOrdersBuilderInterface::VIEW_ORDER_TYPE_LIST, $context['tab'] ?? null);
foreach ($viewOrders->getGroups()[0]->getItems() as $viewOrderItem) {
$class = $viewOrderItem->getValueType() ?? $this->getItemClass($form, $viewOrderItem);
if (self::KEY_NOT_FOUND === $class) {
continue;
}
switch ($class) {
case CheckboxType::class:
$type = 'boolean';
break;
case NumberType::class:
case IntegerType::class:
$type = 'number';
break;
case TextareaType::class:
$type = self::TYPE_LONGTEXT;
break;
case TextType::class:
case ChoiceType::class:
$type = 'string';
break;
case CustomerFileType::class:
$type = 'file';
if (str_contains($viewOrderItem->getKey(), 'image')) {
$type = 'image';
}
break;
case self::TYPE_FILES:
case CollectionType::class:
if ('customerFiles' === $viewOrderItem->getKey()) {
$type = 'files';
}
break;
case DateType::class:
$type = 'date';
break;
case DateTimeType::class:
$type = 'datetime';
break;
case self::TYPE_TEL:
case self::TYPE_MONEY:
case self::TYPE_PERCENT:
case self::TYPE_EMAIL:
case self::TYPE_HTML:
$type = $class;
break;
default:
$type = 'unknown';
}
switch ($viewOrderItem->getKey()) {
case 'socialCapital':
case 'turnover':
case 'weightedTotal':
case 'totalExcludingVat':
$type = self::TYPE_MONEY;
break;
case 'phone':
case 'assistantPhone':
case 'fax':
case 'mobile':
$type = self::TYPE_TEL;
break;
case 'potential':
$type = self::TYPE_PERCENT;
break;
}
$label = $viewOrderItem->getLabel() ?? $viewOrderItem->getKey();
$sortKey = $viewOrderItem->getKey();
$fieldOfForm = $this->formFieldExtractor->getAllFormFieldNamesFromEntity($entityFQCN)[$viewOrderItem->getKey()] ?? null;
if ($fieldOfForm instanceof FormInterface) {
$label = $fieldOfForm->getConfig()->getOption('label', $label) ?? $label;
$attr = $fieldOfForm->getConfig()->getOption('attr', []) ?? [];
if (!empty($attr[self::FORM_SORT_KEY])) {
$sortKey = $attr[self::FORM_SORT_KEY];
}
}
$headerEntry = $this->headerEntryBuilder
->getFormatter($viewOrderItem, $entityFQCN, $type ?? 'unknown', $class)
->build($viewOrderItem, $entityFQCN, $type ?? 'unknown', $class, $label, $sortKey)
;
$replacementResponse->addHeader($headerEntry);
}
$replacementResponse->addHeader(
(new HeaderEntry())
->setKey('actions')
->setLabel('')
->addMetadata('type', 'rowActions')
->addMetadata(HeaderEntry::KEY_SORT_TYPE, HeaderEntry::VALUE_SORT_TYPE_DISABLED)
);
foreach ($entities as $entity) {
$resultEntry = $this->resultEntryBuilder
->getFormatter($entity, $entityFQCN)
->build($entity, $entityFQCN)
;
if ($needToAddProspectFullname) {
$fieldEntry = new FieldEntry();
$value = $this->exportBuilder
->getExporter($entity, $entityFieldFullname, ExporterInterface::EXPORT_TYPE_LISTING)
->convert($entity, $entityFieldFullname);
$fieldEntry
->setKey($entityFieldFullname)
->setValue($value);
$resultEntry->addField($fieldEntry);
}
foreach ($viewOrders->getGroups()[0]->getItems() as $viewOrderItem) {
$property = $viewOrderItem->getKey();
$fieldEntry = new FieldEntry();
$value = $this->exportBuilder
->getExporter($entity, $property, ExporterInterface::EXPORT_TYPE_LISTING)
->convert($entity, $property);
if (in_array($viewOrderItem->getKey(), ContactConcernedExporter::FIELDS_SUPPORTED, true)
&& $entity instanceof Task) {
$isUnknown = false;
foreach ($entity->getContacts() as $contact) {
$isUnknown = $contact->isUnknown();
if ($isUnknown) {
break;
}
}
$fieldEntry->addMetadata('isUnknown', $isUnknown);
}
if (in_array($viewOrderItem->getKey(), LongtextExporter::FIELDS_SUPPORTED, true)) {
$fieldEntry->addMetadata('tooltip', $value);
$value = strlen($value) > self::LONGTEXT_LENGTH_MAX
? mb_substr($value, 0, self::LONGTEXT_LENGTH_MAX, 'UTF-8').'...'
: $value
;
$fieldEntry
->setKey($property)
->setValue($value)
;
$resultEntry->addField($fieldEntry);
continue;
}
$fieldEntry
->setKey($property)
->setValue($this->exportBuilder
->getExporter($entity, $property, ExporterInterface::EXPORT_TYPE_LISTING)
->convert($entity, $property))
;
$resultEntry->addField($fieldEntry);
}
$resultEntry->setRowActions($this->actionBuilder->getActions($entity));
$replacementResponse->addResult($resultEntry);
}
return $this->normalizer->normalize($replacementResponse);
}
/**
* @param FormInterface $form
* @param Item $viewOrderItem
*
* @return string
*/
private function getItemClass(FormInterface $form, Item $viewOrderItem): string
{
$fieldName = $viewOrderItem->getKey();
$formItem = null;
if ($form->has($fieldName)) {
$formItem = $form->get($fieldName);
}
if (null === $formItem) {
$explodedFieldName = explode('_', $fieldName);
foreach ($explodedFieldName as $key => $part) {
if ('sf' === $part) {
// From here, this is the specificField fieldName
$specificFieldFieldName = implode('_', array_slice($explodedFieldName, $key));
if ($form->has($specificFieldFieldName)) {
$formItem = $form->get($specificFieldFieldName);
break;
}
continue;
}
if ($form->has($part)) {
$form = $form->get($part);
}
if ($part === end($explodedFieldName)) {
$formItem = $form;
break;
}
}
}
return null === $formItem
? self::KEY_NOT_FOUND
: get_class($formItem->getConfig()->getType()->getInnerType())
;
}
}