<?php
namespace App\Controller\Admin;
use App\Controller\Admin\Filter\DateCalendarFilter;
use App\Entity\Campaign;
use App\Entity\FormActionsSet;
use App\Entity\FormLead;
use App\Event\ActionFormEvent;
use App\Repository\CampaignRepository;
use App\Repository\FormLeadRepository;
use App\Security\Voter\FormLeadVoter;
use App\Service\FormLeadService;
use App\Service\JsonFormManager;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use League\Csv\CannotInsertRecord;
use League\Csv\InvalidArgument;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
class FormLeadCrudController extends AbstractCrudController
{
/** @var EventDispatcherInterface $dispatcher */
private $dispatcher;
/** @var AdminUrlGenerator $adminUrlGenerator */
private $adminUrlGenerator;
/** @var Campaign $campaign */
private $campaign;
/** @var FormLeadService $formLeadService */
private $formLeadService;
/** @var FormLeadRepository $repository */
private $repository;
/**
* @param EventDispatcherInterface $dispatcher
* @param AdminUrlGenerator $adminUrlGenerator
* @param FormLeadService $formLeadService
* @param FormLeadRepository $repository
*/
public function __construct(
EventDispatcherInterface $dispatcher,
AdminUrlGenerator $adminUrlGenerator,
FormLeadService $formLeadService,
FormLeadRepository $repository
) {
$this->dispatcher = $dispatcher;
$this->adminUrlGenerator = $adminUrlGenerator;
$this->formLeadService = $formLeadService;
$this->repository = $repository;
}
/**
* @param AdminContext $context
* @return KeyValueStore|RedirectResponse|Response
*/
public function index(AdminContext $context)
{
$this->campaign = $this->get('doctrine')->getRepository(Campaign::class)
->find((int) $context->getRequest()->query->get('entityId'))
;
return parent::index($context);
}
/**
* @return string
*/
public static function getEntityFqcn(): string
{
return FormLead::class;
}
/**
* @param Crud $crud
* @return Crud
*/
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityLabelInPlural('FormLeads')
->setPageTitle('index', '%entity_label_plural% de ')
->setEntityPermission(FormLeadVoter::VIEW)
->overrideTemplates([
'crud/index' => 'admin/crud/lead/index.html.twig',
])
->setSearchFields(['id', 'formLeadData.value'])
;
}
/**
* @param string $pageName
* @return iterable
*/
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id')->hideOnForm(),
TextField::new('uuid')->hideOnForm()->hideOnIndex(),
AssociationField::new('formLeadData')->setTemplatePath('admin/field/form-lead-data.html.twig')->hideOnIndex(),
BooleanField::new('active')->hideOnForm(),
DateTimeField::new('periodStartsAt')->hideOnForm(),
DateTimeField::new('periodUpdatedAt')->hideOnForm(),
BooleanField::new('eventForced')->hideOnForm()
];
}
/**
* @param Filters $filters
* @return Filters
*/
public function configureFilters(Filters $filters): Filters
{
return $filters
->add('active')
->add(DateCalendarFilter::new('periodStartsAt'))
->add(DateCalendarFilter::new('periodUpdatedAt'))
;
}
/**
* @param Actions $actions
* @return Actions
*/
public function configureActions(Actions $actions): Actions
{
$executeActions = Action::new('executeActions', 'Enviar Renovación')
->linkToCrudAction('executeActions')
;
$returnList = Action::new('indexByCampaign', 'Volver al listado')
->linkToRoute('index_by_campaign', function (FormLead $lead): array {
return [
'id' => $lead->getId()
];
})
;
$exportLeads = Action::new('exportAllLeads', 'Exportar')
->linkToCrudAction('exportAllLeads')
->addCssClass('btn btn-primary')
->setIcon('fas fa-file-export')
->createAsGlobalAction()
;
$exportLeadsWithFilters = Action::new('exportLeadsWithFilters', 'Exportar con filtros')
->linkToCrudAction('exportLeadsWithFilters')
->addCssClass('btn btn-primary')
->setIcon('fas fa-file-export')
->createAsGlobalAction()
;
return $actions
->add(Crud::PAGE_INDEX, $exportLeads)
->add(Crud::PAGE_INDEX, $exportLeadsWithFilters)
->add(Crud::PAGE_INDEX, $executeActions)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->remove(Crud::PAGE_INDEX, Action::DELETE)
->remove(Crud::PAGE_INDEX, Action::EDIT)
->remove(Crud::PAGE_INDEX, Action::NEW)
->remove(Crud::PAGE_DETAIL, Action::DELETE)
->remove(Crud::PAGE_DETAIL, Action::EDIT)
->remove(Crud::PAGE_DETAIL, Action::INDEX)
->add(Crud::PAGE_DETAIL, $returnList)
;
}
/**
* @param SearchDto $searchDto
* @param EntityDto $entityDto
* @param FieldCollection $fields
* @param FilterCollection $filters
* @return QueryBuilder
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
$queryBuilder = $this->container->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
if (!$this->campaign) {
$result = $queryBuilder->getQuery()->getResult();
if (isset($result[0]) && $result[0] instanceof FormLead) {
$this->campaign = $result[0]->getCampaign();
}
}
if (!$this->campaign) {
return $queryBuilder;
}
$queryBuilder
->andWhere('entity.campaign = :campaign')
->setParameter('campaign', $this->campaign->getId())
;
return $queryBuilder;
}
/**
* @param AdminContext $context
* @param FormLeadRepository $repository
* @return RedirectResponse
* @throws ORMException
* @throws OptimisticLockException
*/
public function executeActions(AdminContext $context, FormLeadRepository $repository): RedirectResponse
{
/** @var FormLead $lead */
$lead = $context->getEntity()->getInstance();
if (!$lead->isActive()) {
$this->addFlash('warning', 'El registro no está activo. No se ha ejecutado ninguna acción');
return $this->redirect($context->getReferrer());
}
$campaign = $lead->getCampaign();
foreach ($campaign->getForms() as $form) {
foreach ($form->getFormActionsSets() as $actionsSet) {
if (FormActionsSet::EVENT_FORCED !== $actionsSet->getEvent()) {
continue;
}
// Dispatch Event
$event = new ActionFormEvent($form, $lead, $actionsSet->getEvent());
$this->dispatcher->dispatch($event, ActionFormEvent::KEY);
// Update lead
$lead->setEventForced(true);
$repository->store($lead);
}
}
return $this->redirect($context->getReferrer());
}
/**
* @Route(name="index_by_campaign")
* @param FormLead $lead
* @return RedirectResponse
*/
public function indexByCampaign(FormLead $lead): RedirectResponse
{
$url = $this->adminUrlGenerator
->setController(FormLeadCrudController::class)
->setAction(Action::INDEX)
->setEntityId($lead->getCampaign()->getId())
->generateUrl();
return $this->redirect($url);
}
/**
* @param AdminContext $context
* @return BinaryFileResponse|RedirectResponse
* @throws CannotInsertRecord
* @throws InvalidArgument
*/
public function exportAllLeads(AdminContext $context)
{
return $this->exportLeads($context);
}
/**
* @param AdminContext $context
* @param CampaignRepository $campaignRepository
* @return BinaryFileResponse|RedirectResponse
* @throws CannotInsertRecord
* @throws InvalidArgument
*/
public function exportLeadsWithFilters(AdminContext $context, CampaignRepository $campaignRepository)
{
$referrer = $context->getReferrer();
$campaignId = $this->getCampaignByReferrer($referrer);
if (!$campaignId) {
$this->addFlash('danger', 'No se encuentra la campaña');
return $this->redirect($referrer);
}
$campaign = $campaignRepository->find($campaignId);
if (!$campaign->getExportLeadFields()) {
$this->addFlash('warning', 'No hay filtros definidos en la campaña');
return $this->redirect($referrer);
}
$filters = [];
foreach ($campaign->getExportLeadFields() as $field) {
$filters[] = [
'field' => JsonFormManager::getNameFromFieldName($field),
'type' => JsonFormManager::getTypeFromFieldName($field)
];
}
return $this->exportLeads($context, $filters);
}
/**
* @param Campaign $campaign
* @return string
*/
public function getCampaignDetailUrl(Campaign $campaign): string
{
return $this->adminUrlGenerator
->setController(CampaignCrudController::class)
->setAction(Action::DETAIL)
->setEntityId($campaign->getId())
->generateUrl()
;
}
/**
* @param KeyValueStore $responseParameters
* @return KeyValueStore
*/
public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore
{
if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
$addParameters = [
'campaign' => $this->campaign,
'campaign_detail_url' => $this->getCampaignDetailUrl($this->campaign)
];
foreach ($addParameters as $key => $value) {
$responseParameters->set($key, $value);
}
}
return $responseParameters;
}
/**
* @param string $referrer
* @return null
*/
private function getCampaignByReferrer(string $referrer): ?int
{
$referrer = explode('&', $referrer);
foreach ($referrer as $item) {
$entityIndex = 'entityId=';
if (str_contains($item, $entityIndex)) {
return (int) explode($entityIndex, $item)[1];
}
}
return null;
}
/**
* @param AdminContext $context
* @param array $filters
* @return BinaryFileResponse|RedirectResponse
* @throws CannotInsertRecord
* @throws InvalidArgument
*/
public function exportLeads(AdminContext $context, array $filters = [])
{
ini_set('max_execution_time', '-1');
set_time_limit(0);
$referrer = $context->getReferrer();
$campaignId = $this->getCampaignByReferrer($referrer);
if (!$campaignId) {
$this->addFlash('danger', 'No se encuentra la campaña');
return $this->redirect($referrer);
}
$leads = $this->repository->findBy(['campaign' => $campaignId]);
if (empty($leads)) {
$this->addFlash('warning', 'No hay registros');
return $this->redirect($referrer);
}
$fileName = $this->formLeadService->exportLeads($campaignId, $leads, $filters);
if ('' === $fileName) {
$this->addFlash('warning', 'No se han encontrado registros');
return $this->redirect($referrer);
}
if (null === $fileName) {
$this->addFlash('danger', 'Se ha producido un error');
return $this->redirect($referrer);
}
$response = new BinaryFileResponse(
$fileName, 200, []
);
return $response
->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT)
->deleteFileAfterSend()
;
}
}