Browse Source

Mis à jour import

develop
Fabien Normand 3 years ago
parent
commit
7d7614d4e6
58 changed files with 1141 additions and 580 deletions
  1. +15
    -57
      Builder/Ticket/TicketBuilder.php
  2. +10
    -18
      Builder/Ticket/TicketMessageBuilder.php
  3. +10
    -1
      Container/Ticket/TicketContainer.php
  4. +297
    -256
      Controller/AbstractAdminController.php
  5. +2
    -0
      Controller/Reminder/ReminderAdminController.php
  6. +80
    -104
      Controller/Ticket/TicketAdminController.php
  7. +39
    -8
      Controller/User/UserAdminController.php
  8. +3
    -0
      Definition/ActionDefinition.php
  9. +17
    -2
      Definition/Field/AbstractFieldDefinition.php
  10. +2
    -2
      Definition/Field/Site/NewsFieldDefinition.php
  11. +118
    -0
      Definition/Field/Ticket/TicketFieldDefinition.php
  12. +15
    -2
      Definition/Field/User/UserFieldDefinition.php
  13. +0
    -17
      Definition/SiteSettingDefinition.php
  14. +30
    -0
      Event/Ticket/TicketEvent.php
  15. +0
    -1
      EventSubscriber/SiteSettingEventSubscriber.php
  16. +138
    -0
      EventSubscriber/Ticket/SendNotificationTicketEventSubscriber.php
  17. +2
    -0
      Factory/Site/NewsFactory.php
  18. +2
    -0
      Factory/Site/PageFactory.php
  19. +2
    -0
      Factory/User/GroupUserFactory.php
  20. +1
    -1
      Field/BooleanField.php
  21. +1
    -14
      Field/Filter/ChoiceFilter.php
  22. +11
    -12
      Field/Filter/FilterManager.php
  23. +3
    -3
      Field/Filter/FilterTrait.php
  24. +38
    -0
      Field/Filter/Ticket/TicketEmailFilter.php
  25. +38
    -0
      Field/Filter/Ticket/TicketFirstnameFilter.php
  26. +38
    -0
      Field/Filter/Ticket/TicketLastnameFilter.php
  27. +8
    -11
      Form/Ticket/TicketFormType.php
  28. +7
    -7
      Form/Ticket/TicketMessageAdminFormType.php
  29. +9
    -10
      Form/Ticket/TicketMessageType.php
  30. +1
    -2
      Model/Ticket/TicketMessageModel.php
  31. +1
    -2
      Model/Ticket/TicketModel.php
  32. +1
    -1
      Model/User/UserModel.php
  33. +1
    -3
      Repository/AbstractRepositoryQuery.php
  34. +41
    -0
      Repository/Ticket/TicketRepositoryQuery.php
  35. +13
    -0
      Repository/User/GroupUserRepositoryQuery.php
  36. +1
    -0
      Repository/User/GroupUserStore.php
  37. +16
    -0
      Repository/User/UserRepositoryQuery.php
  38. +10
    -0
      Resources/assets/app/adminlte/index/index.scss
  39. +1
    -2
      Resources/assets/app/adminlte/sort/sort.js
  40. +5
    -4
      Resources/translations/admin.fr.yaml
  41. +3
    -0
      Resources/views/admin/ticket/detail.html.twig
  42. +32
    -7
      Resources/views/admin/ticket/field/lastmessage.html.twig
  43. +2
    -0
      Resources/views/admin/ticket/field/status.html.twig
  44. +1
    -1
      Resources/views/admin/ticket/macro.html.twig
  45. +4
    -2
      Resources/views/adminlte/block/menu.html.twig
  46. +8
    -8
      Resources/views/adminlte/block/navbar_header.html.twig
  47. +12
    -0
      Resources/views/adminlte/crud/field/association.html.twig
  48. +3
    -6
      Resources/views/adminlte/crud/field/toggle.html.twig
  49. +6
    -0
      Resources/views/adminlte/crud/form_theme.html.twig
  50. +7
    -5
      Resources/views/adminlte/crud/index.html.twig
  51. +7
    -1
      Resources/views/adminlte/crud/sort.html.twig
  52. +0
    -2
      Resources/views/adminlte/layout.html.twig
  53. +5
    -1
      Resources/views/adminlte/macro/badge.html.twig
  54. +3
    -2
      Solver/Ticket/TicketSolver.php
  55. +2
    -2
      Translation/TranslatorAdmin.php
  56. +1
    -1
      Twig/StoreTwigExtension.php
  57. +2
    -2
      Twig/TranslatorTwigExtension.php
  58. +16
    -0
      Twig/TwigExtension.php

+ 15
- 57
Builder/Ticket/TicketBuilder.php View File

namespace Lc\SovBundle\Builder\Ticket; namespace Lc\SovBundle\Builder\Ticket;


use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Event\Ticket\TicketEvent;
use Lc\SovBundle\Notification\MailMailjetNotification; use Lc\SovBundle\Notification\MailMailjetNotification;
use Lc\SovBundle\Component\FormComponent; use Lc\SovBundle\Component\FormComponent;
use Lc\SovBundle\Factory\Ticket\TicketFactory; use Lc\SovBundle\Factory\Ticket\TicketFactory;
use Lc\SovBundle\Model\Ticket\TicketModel; use Lc\SovBundle\Model\Ticket\TicketModel;
use Lc\SovBundle\Repository\User\UserStore; use Lc\SovBundle\Repository\User\UserStore;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;


protected TicketFactory $ticketFactory; protected TicketFactory $ticketFactory;
protected AuthorizationCheckerInterface $authorizationChecker; protected AuthorizationCheckerInterface $authorizationChecker;
protected UserStore $userStore; protected UserStore $userStore;
protected EventDispatcherInterface $eventDispatcher;



public function __construct( public function __construct(
Security $security, Security $security,
ParameterBagInterface $parameterBag, ParameterBagInterface $parameterBag,
AuthorizationCheckerInterface $authorizationChecker, AuthorizationCheckerInterface $authorizationChecker,
TicketFactory $ticketFactory, TicketFactory $ticketFactory,
UserStore $userStore
UserStore $userStore,
EventDispatcherInterface $eventDispatcher
) { ) {
$this->security = $security; $this->security = $security;
$this->entityManager = $entityManager; $this->entityManager = $entityManager;
$this->ticketFactory = $ticketFactory; $this->ticketFactory = $ticketFactory;
$this->userStore = $userStore; $this->userStore = $userStore;
$this->authorizationChecker = $authorizationChecker; $this->authorizationChecker = $authorizationChecker;
$this->eventDispatcher = $eventDispatcher;
} }


public function create(array $params = []): TicketInterface public function create(array $params = []): TicketInterface


$this->init($ticket, $params); $this->init($ticket, $params);


$user = $ticket->getUser();
if ($ticket->getUser()) {
$email = $user->getEmail();
$firstname = $user->getFirstname();
} else {
$email = $params['visitorEmail'];
$firstname = $params['visitorFirstname'];
}


$this->entityManager->create($ticket); $this->entityManager->create($ticket);
$this->entityManager->flush(); $this->entityManager->flush();


if (isset($params['createByAdmin']) && $params['createByAdmin']) {
// envoi email au client
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Vous avez reçu un nouveau message',
MailMailjetNotification::TO_EMAIL => $email,
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new-by-admin',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
} else {
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Nouvelle demande',
MailMailjetNotification::TO_EMAIL => $email,
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
}

// notifyAdmin
$usersToNotify = $this->userStore->getByTicketTypesNotification($ticket->getType());

foreach ($usersToNotify as $userToNotify) {
if ($this->authorizationChecker->isGranted('ROLE_ADMIN', $userToNotify)) {
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Nouveau ticket sur Place du Local',
MailMailjetNotification::TO_EMAIL => $userToNotify->getEmail(),
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-notification',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $userToNotify->getFirstname(),
'ticket' => $ticket,
'ticketMessage' => $ticket->getTicketMessages()[0],
],
]
);
}
}
$this->eventDispatcher->dispatch(new TicketEvent($ticket), TicketEvent::NEW_TICKET_EVENT);


return $ticket; return $ticket;
} }
public function init(TicketInterface $ticket, array $params = []): void public function init(TicketInterface $ticket, array $params = []): void
{ {
$user = $this->security->getUser(); $user = $this->security->getUser();
if($user) {
if ($user) {
$ticket->setCreatedBy($user); $ticket->setCreatedBy($user);
} }


if (isset($params['section'])) {
$ticket->setSection($params['section']);
}
$ticket->setMerchant($params['merchant']);

if (isset($params['user'])) { if (isset($params['user'])) {
$ticket->setUser($params['user']); $ticket->setUser($params['user']);

} else { } else {
$ticket->setVisitorFirstname($params['visitorFirstname']); $ticket->setVisitorFirstname($params['visitorFirstname']);
$ticket->setVisitorLastname($params['visitorLastname']); $ticket->setVisitorLastname($params['visitorLastname']);

+ 10
- 18
Builder/Ticket/TicketMessageBuilder.php View File

namespace Lc\SovBundle\Builder\Ticket; namespace Lc\SovBundle\Builder\Ticket;


use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Event\Ticket\TicketEvent;
use Lc\SovBundle\Notification\MailMailjetNotification; use Lc\SovBundle\Notification\MailMailjetNotification;
use Lc\SovBundle\Component\FormComponent; use Lc\SovBundle\Component\FormComponent;
use Lc\SovBundle\Factory\Ticket\TicketFactory; use Lc\SovBundle\Factory\Ticket\TicketFactory;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
use Lc\SovBundle\Model\Ticket\TicketModel; use Lc\SovBundle\Model\Ticket\TicketModel;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;


class TicketMessageBuilder class TicketMessageBuilder
{ {
protected EntityManagerInterface $entityManager; protected EntityManagerInterface $entityManager;
protected MailMailjetNotification $mailMailjetNotification; protected MailMailjetNotification $mailMailjetNotification;
protected TicketMessageFactory $ticketMessageFactory; protected TicketMessageFactory $ticketMessageFactory;
protected EventDispatcherInterface $eventDispatcher;


public function __construct( public function __construct(
EntityManagerInterface $entityManager, EntityManagerInterface $entityManager,
MailMailjetNotification $mailMailjetNotification, MailMailjetNotification $mailMailjetNotification,
TicketMessageFactory $ticketMessageFactory
TicketMessageFactory $ticketMessageFactory,
EventDispatcherInterface $eventDispatcher
) { ) {
$this->entityManager = $entityManager; $this->entityManager = $entityManager;
$this->mailMailjetNotification = $mailMailjetNotification; $this->mailMailjetNotification = $mailMailjetNotification;
$this->ticketMessageFactory = $ticketMessageFactory; $this->ticketMessageFactory = $ticketMessageFactory;
$this->eventDispatcher = $eventDispatcher;
} }


public function create(array $params = []): TicketMessageInterface public function create(array $params = []): TicketMessageInterface
$ticketMessage->setStatus(1); $ticketMessage->setStatus(1);
$ticketMessage->setTicket($ticket); $ticketMessage->setTicket($ticket);
$ticketMessage->setMessage($params['message']); $ticketMessage->setMessage($params['message']);

if (isset($params['answerByAdmin']) && $params['answerByAdmin']) { if (isset($params['answerByAdmin']) && $params['answerByAdmin']) {
$ticketMessage->setAnswerByAdmin($params['answerByAdmin']); $ticketMessage->setAnswerByAdmin($params['answerByAdmin']);

// envoi email au client
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Réponse à votre demande',
MailMailjetNotification::TO_EMAIL => $ticket->getUser() ? $ticket->getUser()->getEmail(
) : $ticket->getVisitorEmail(),
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-response',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $ticket->getUser() ? $ticket->getUser()->getFirstname(
) : $ticket->getVisitorFirstname(),
'ticket' => $ticket,
],
]
);
} }
$this->entityManager->persist($ticketMessage); $this->entityManager->persist($ticketMessage);




$ticket->setUpdatedAt(new \DateTime()); $ticket->setUpdatedAt(new \DateTime());


$this->entityManager->persist($ticket);
$this->entityManager->create($ticket);
$this->entityManager->flush(); $this->entityManager->flush();


$this->eventDispatcher->dispatch(new TicketEvent($ticket), TicketEvent::NEW_MESSAGE_EVENT);


return $ticketMessage; return $ticketMessage;
} }



+ 10
- 1
Container/Ticket/TicketContainer.php View File

namespace Lc\SovBundle\Container\Ticket; namespace Lc\SovBundle\Container\Ticket;


use Lc\SovBundle\Builder\Ticket\TicketBuilder; use Lc\SovBundle\Builder\Ticket\TicketBuilder;
use Lc\SovBundle\Definition\Field\Ticket\TicketFieldDefinition;
use Lc\SovBundle\Factory\Ticket\TicketFactory; use Lc\SovBundle\Factory\Ticket\TicketFactory;
use Lc\SovBundle\Repository\Ticket\TicketRepositoryQuery; use Lc\SovBundle\Repository\Ticket\TicketRepositoryQuery;
use Lc\SovBundle\Repository\Ticket\TicketStore; use Lc\SovBundle\Repository\Ticket\TicketStore;
protected TicketRepositoryQuery $repositoryQuery; protected TicketRepositoryQuery $repositoryQuery;
protected TicketStore $store; protected TicketStore $store;
protected TicketSolver $solver; protected TicketSolver $solver;
protected TicketFieldDefinition $fieldDefinition;


public function __construct( public function __construct(
TicketFactory $factory, TicketFactory $factory,
TicketBuilder $builder, TicketBuilder $builder,
TicketRepositoryQuery $repositoryQuery, TicketRepositoryQuery $repositoryQuery,
TicketStore $store, TicketStore $store,
TicketSolver $solver
TicketSolver $solver,
TicketFieldDefinition $fieldDefinition
) { ) {
$this->factory = $factory; $this->factory = $factory;
$this->builder = $builder; $this->builder = $builder;
$this->repositoryQuery = $repositoryQuery; $this->repositoryQuery = $repositoryQuery;
$this->store = $store; $this->store = $store;
$this->solver = $solver; $this->solver = $solver;
$this->fieldDefinition = $fieldDefinition;
} }


public function getFactory(): TicketFactory public function getFactory(): TicketFactory
{ {
return $this->solver; return $this->solver;
} }

public function getFieldDefinition(): TicketFieldDefinition
{
return $this->fieldDefinition;
}
} }

+ 297
- 256
Controller/AbstractAdminController.php View File

use Lc\SovBundle\Doctrine\Extension\DevAliasInterface; use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\SeoInterface; use Lc\SovBundle\Doctrine\Extension\SeoInterface;
use Lc\SovBundle\Doctrine\Extension\SortableInterface; use Lc\SovBundle\Doctrine\Extension\SortableInterface;
use Lc\SovBundle\Doctrine\Extension\StatusInterface;
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface; use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
use Lc\SovBundle\Doctrine\Extension\TreeInterface; use Lc\SovBundle\Doctrine\Extension\TreeInterface;
use Lc\SovBundle\Field\CollectionField; use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\Filter\FilterManager; use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Form\Common\FiltersFormType; use Lc\SovBundle\Form\Common\FiltersFormType;
use Lc\SovBundle\Form\Common\PositionType; use Lc\SovBundle\Form\Common\PositionType;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\EntityRepository; use Lc\SovBundle\Repository\EntityRepository;
use Lc\SovBundle\Repository\RepositoryQueryInterface; use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\FlashBagTranslator; use Lc\SovBundle\Translation\FlashBagTranslator;
use ControllerTrait; use ControllerTrait;


protected FormInterface $filtersForm; protected FormInterface $filtersForm;
protected bool $isRepositoryQueryFiltered = false;


abstract public function getRepositoryQuery(): RepositoryQueryInterface; abstract public function getRepositoryQuery(): RepositoryQueryInterface;


if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
$responseParameters->set('fields', $this->configureFields('index')); $responseParameters->set('fields', $this->configureFields('index'));


//TODO supprimer ce code rapport au filtre dans les index
/*if ($this->filtersForm === null) {
die('nncncd');

$options['fields'] = $responseParameters->get('fields');
$options['entity_class'] = $this->getEntityFqcn();
$options['entity_name'] = $responseParameters->get('entity')->getName();
$this->filtersForm = $this->createForm(FiltersFormType::class, null, $options);
}*/
$responseParameters->set('filters_form', $this->filtersForm);
if(isset($this->filtersForm)) {
$responseParameters->set('filters_form', $this->filtersForm);
}
} }


$responseParameters->set('translation_entity_name', $this->getTranslationEntityName()); $responseParameters->set('translation_entity_name', $this->getTranslationEntityName());
if ($entity !== null) { if ($entity !== null) {
if ($entity->getParent() !== null) { if ($entity->getParent() !== null) {
$url = $adminUrlGenerator $url = $adminUrlGenerator
->setController($context->getCrud()->getControllerFqcn())
->set('entityId', $entity->getParent()->getId())
->generateUrl();
->setController($context->getCrud()->getControllerFqcn())
->set('entityId', $entity->getParent()->getId())
->generateUrl();
$action->setLinkUrl($url); $action->setLinkUrl($url);
} }
} else { } else {
$entityId = $context->getRequest()->get('entityId'); $entityId = $context->getRequest()->get('entityId');
if ($entityId != null) { if ($entityId != null) {
$url = $adminUrlGenerator $url = $adminUrlGenerator
->setController($context->getCrud()->getControllerFqcn())
->setAction($action->getName())
->set('entityId', $entityId)
->generateUrl();
->setController($context->getCrud()->getControllerFqcn())
->setAction($action->getName())
->set('entityId', $entityId)
->generateUrl();
$action->setLinkUrl($url); $action->setLinkUrl($url);
} }
} }
if ($action->getName() == ActionDefinition::WRITE_TO_USER) {
$entity = $context->getEntity()->getInstance();
if ($entity !== null) {
if(method_exists($entity, 'getUser')){
$url = $this->generateEaUrl(UserA) ->setController($context->getCrud()->getControllerFqcn())
->set('entityId', $entity->getParent()->getId())
->generateUrl();
$action->setLinkUrl($url);
}
} else {
unset($actions[$i]);
}
}
} }
} }
} }


protected function getRequestCrudAction() :string{
return $this->getRequestStack()->getCurrentRequest()->get('crudAction');
}

public function configureCrud(Crud $crud): Crud public function configureCrud(Crud $crud): Crud
{ {
$crud = parent::configureCrud($crud); $crud = parent::configureCrud($crud);

$this->setMaxResults($crud);
if($this->getRequestCrudAction() === ActionDefinition::SORT) {
$crud->setPaginatorPageSize(9999);
}else {
$this->setMaxResults($crud);
}


$crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]); $crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]);


$this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults); $this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults);
} }
$maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get( $maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get(
$paramSessionListMaxResults
$paramSessionListMaxResults
) : 30; ) : 30;


$crud->setPaginatorPageSize($maxResults); $crud->setPaginatorPageSize($maxResults);
{ {
if ($this->isInstanceOf(SeoInterface::class)) { if ($this->isInstanceOf(SeoInterface::class)) {
return [ return [
FormField::addPanel('seo')->setTemplateName('crud/field/generic'),
TextField::new('metaTitle')->setLabel('Meta Title')->setHelp(
'Affiché dans les résultats de recherche Google'
)->hideOnIndex(),
TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp(
'Affiché dans les résultats de recherche Google'
FormField::addPanel('seo')->setTemplateName('crud/field/generic'),
TextField::new('metaTitle')->setLabel('Meta Title')->setHelp(
'Affiché dans les résultats de recherche Google'
)->hideOnIndex(),
TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp(
'Affiché dans les résultats de recherche Google'
)->hideOnIndex(),
CollectionField::new('oldUrls')
->setFormTypeOption('entry_type', TextType::class)->setLabel(
'Anciennes urls du document'
)->hideOnIndex(), )->hideOnIndex(),
CollectionField::new('oldUrls')
->setFormTypeOption('entry_type', TextType::class)->setLabel(
'Anciennes urls du document'
)->hideOnIndex(),
]; ];
} else { } else {
return null; return null;
{ {
if ($this->isInstanceOf(DevAliasInterface::class)) { if ($this->isInstanceOf(DevAliasInterface::class)) {
return [ return [
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'),
TextField::new('devAlias')->hideOnIndex(),
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'),
TextField::new('devAlias')->hideOnIndex(),
]; ];
} else { } else {
return null; return null;


$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
$filters = $this->get(FilterFactory::class)->create( $filters = $this->get(FilterFactory::class)->create(
$context->getCrud()->getFiltersConfig(),
$fields,
$context->getEntity()
$context->getCrud()->getFiltersConfig(),
$fields,
$context->getEntity()
); );
$queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);

$queryBuilder = $this->createSortQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);
$paginator = $this->get(PaginatorFactory::class)->create($queryBuilder); $paginator = $this->get(PaginatorFactory::class)->create($queryBuilder);


$entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults()); $entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults());
$this->get(EntityFactory::class)->processFieldsForAll($entities, $fields); $this->get(EntityFactory::class)->processFieldsForAll($entities, $fields);


$sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults())) $sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults()))
->add(
'entities',
CollectionType::class,
array(
'required' => true,
'allow_add' => true,
'entry_type' => PositionType::class,
)
->add(
'entities',
CollectionType::class,
array(
'required' => true,
'allow_add' => true,
'entry_type' => PositionType::class,
) )
->getForm();
)
->getForm();


$entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn()); $entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn());
$repository = $entityManager->getRepository($this->getEntityFqcn()); $repository = $entityManager->getRepository($this->getEntityFqcn());
} }


$url = $this->get(AdminUrlGenerator::class) $url = $this->get(AdminUrlGenerator::class)
->setAction(ActionDefinition::INDEX)
->generateUrl();
->setAction(ActionDefinition::INDEX)
->generateUrl();
$this->addFlashTranslator('success', 'sorted'); $this->addFlashTranslator('success', 'sorted');


return $this->redirect($url); return $this->redirect($url);
} }


$responseParameters = $this->configureResponseParameters( $responseParameters = $this->configureResponseParameters(
KeyValueStore::new(
[
'pageName' => Crud::PAGE_INDEX,
'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
'entities' => $entities,
'paginator' => $paginator,
'global_actions' => array(),
'batch_actions' => array(),
'filters' => $filters,
'sortable_form' => $sortableForm,
]
)
KeyValueStore::new(
[
'pageName' => Crud::PAGE_INDEX,
'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
'entities' => $entities,
'paginator' => $paginator,
'global_actions' => array(),
'batch_actions' => array(),
'filters' => $filters,
'sortable_form' => $sortableForm,
]
)
); );
$responseParameters->set('fields', $this->configureFields('index')); $responseParameters->set('fields', $this->configureFields('index'));
$event = new AfterCrudActionEvent($context, $responseParameters); $event = new AfterCrudActionEvent($context, $responseParameters);
} }


public function duplicate( public function duplicate(
AdminContext $context,
EntityComponent $entityComponent,
TranslatorAdmin $translatorAdmin,
EntityManagerInterface $em
AdminContext $context,
EntityComponent $entityComponent,
TranslatorAdmin $translatorAdmin,
EntityManagerInterface $em
) { ) {
if (!$this->isGranted( if (!$this->isGranted(
Permission::EA_EXECUTE_ACTION,
['action' => "duplicate", 'entity' => $context->getEntity()]
Permission::EA_EXECUTE_ACTION,
['action' => "duplicate", 'entity' => $context->getEntity()]
)) { )) {
throw new ForbiddenActionException($context); throw new ForbiddenActionException($context);
} }
$em->flush(); $em->flush();


$url = $this->get(AdminUrlGenerator::class) $url = $this->get(AdminUrlGenerator::class)
->setAction(ActionDefinition::EDIT)
->setEntityId($newEntity->getId())
->generateUrl();
->setAction(ActionDefinition::EDIT)
->setEntityId($newEntity->getId())
->generateUrl();


$this->addFlashTranslator('success', 'duplicated'); $this->addFlashTranslator('success', 'duplicated');


return $this->redirect($url); return $this->redirect($url);
} }


public function isRepositoryQueryFiltered():bool{
if(($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered){
return true;
}else{
return false;
}
}
public function createIndexRepositoryQuery( public function createIndexRepositoryQuery(
SearchDto $searchDto, SearchDto $searchDto,
EntityDto $entityDto, EntityDto $entityDto,
FieldCollection $fields, FieldCollection $fields,
FilterCollection $filters FilterCollection $filters
): RepositoryQueryInterface
{
$repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery($this->getRepositoryQuery(), $searchDto, $entityDto, $fields, $filters);
): RepositoryQueryInterface {
$repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
$this->getRepositoryQuery(),
$searchDto,
$entityDto,
$fields,
$filters
);


// TODO : déplacer dans EntotyRepository // TODO : déplacer dans EntotyRepository
if ($this->isInstanceOf(TreeInterface::class)) { if ($this->isInstanceOf(TreeInterface::class)) {
$repositoryQuery->filterIsParent(); $repositoryQuery->filterIsParent();
} }
} }
if ($this->isInstanceOf(StatusInterface::class)) {
$repositoryQuery->filterIsOnlineAndOffline();
}


$this->filtersForm = $this->createForm( $this->filtersForm = $this->createForm(
FiltersFormType::class, FiltersFormType::class,


$this->filtersForm->handleRequest($searchDto->getRequest()); $this->filtersForm->handleRequest($searchDto->getRequest());


$filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto);
$this->isRepositoryQueryFiltered = $filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto);
return $repositoryQuery; return $repositoryQuery;
} }


public function createIndexQueryBuilder(

public function createSortRepositoryQuery(
SearchDto $searchDto, SearchDto $searchDto,
EntityDto $entityDto, EntityDto $entityDto,
FieldCollection $fields, FieldCollection $fields,
FilterCollection $filters FilterCollection $filters
): QueryBuilder {

$repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
return $repositoryQuery->getQueryBuilder();
): RepositoryQueryInterface {
return $this->createIndexRepositoryQuery($searchDto,$entityDto, $fields, $filters);
}
public function createIndexQueryBuilder(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): QueryBuilder {
$repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
return $repositoryQuery->getQueryBuilder();
} }


public function createSortQueryBuilder( public function createSortQueryBuilder(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): QueryBuilder { ): QueryBuilder {
$queryBuilder = $this->createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);

return $queryBuilder;
$repositoryQuery = $this->createSortRepositoryQuery($searchDto, $entityDto, $fields, $filters);
return $repositoryQuery->getQueryBuilder();
} }


public function edit(AdminContext $context) public function edit(AdminContext $context)
$context = $this->get(AdminContextProvider::class)->getContext(); $context = $this->get(AdminContextProvider::class)->getContext();


return $context->getCrudControllers()->findCrudFqcnByEntityFqcn( return $context->getCrudControllers()->findCrudFqcnByEntityFqcn(
$this->get(EntityManagerInterface::class)->getEntityName($interface)
$this->get(EntityManagerInterface::class)->getEntityName($interface)
); );
} }


$entityManager->delete($entityInstance); $entityManager->delete($entityInstance);
$entityManager->flush(); $entityManager->flush();
$this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName()); $this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName());

} }


public function configureActions(Actions $actions): Actions public function configureActions(Actions $actions): Actions
public function getDuplicateAction(): Action public function getDuplicateAction(): Action
{ {
$duplicateAction = Action::new( $duplicateAction = Action::new(
ActionDefinition::DUPLICATE,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE),
'fa fa-fw fa-copy'
ActionDefinition::DUPLICATE,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE),
'fa fa-fw fa-copy'
) )
->linkToCrudAction(ActionDefinition::DUPLICATE)
->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE))
->setCssClass('in-dropdown text-info action-confirm');
->linkToCrudAction(ActionDefinition::DUPLICATE)
->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE))
->setCssClass('in-dropdown text-info action-confirm');


return $duplicateAction; return $duplicateAction;
} }
$actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction()); $actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction());


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_INDEX,
ActionDefinition::NEW,
[
'icon' => 'plus',
'label' => $this->get(TranslatorAdmin::class)->transAction('create'),
'add_class' => 'btn-sm',
]
$actions,
Crud::PAGE_INDEX,
ActionDefinition::NEW,
[
'icon' => 'plus',
'label' => $this->get(TranslatorAdmin::class)->transAction('create'),
'add_class' => 'btn-sm',
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_INDEX,
ActionDefinition::EDIT,
[
'class' => 'btn btn-sm btn-primary',
'icon' => 'edit',
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->get(TranslatorAdmin::class)->transAction('edit'),
),
]
$actions,
Crud::PAGE_INDEX,
ActionDefinition::EDIT,
[
'class' => 'btn btn-sm btn-primary',
'icon' => 'edit',
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->get(TranslatorAdmin::class)->transAction('edit'),
),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_INDEX,
ActionDefinition::DETAIL,
[
'icon' => 'eye',
'add_class' => 'btn btn-sm btn-success',
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->get(TranslatorAdmin::class)->transAction('detail'),
),
]
$actions,
Crud::PAGE_INDEX,
ActionDefinition::DETAIL,
[
'icon' => 'eye',
'add_class' => 'btn btn-sm btn-success',
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->get(TranslatorAdmin::class)->transAction('detail'),
),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_INDEX,
ActionDefinition::DELETE,
[
'icon' => 'trash',
'dropdown' => true,
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
'class' => 'dropdown-item text-danger in-dropdown action-delete',
]
$actions,
Crud::PAGE_INDEX,
ActionDefinition::DELETE,
[
'icon' => 'trash',
'dropdown' => true,
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
'class' => 'dropdown-item text-danger in-dropdown action-delete',
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_INDEX,
ActionDefinition::BATCH_DELETE,
[
'class' => 'btn btn-sm btn-danger',
'icon' => 'trash',
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
]
$actions,
Crud::PAGE_INDEX,
ActionDefinition::BATCH_DELETE,
[
'class' => 'btn btn-sm btn-danger',
'icon' => 'trash',
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
]
); );
} }






$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_RETURN,
[
'add_class' => 'float-right ',
'icon' => 'check',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_RETURN,
[
'add_class' => 'float-right ',
'icon' => 'check',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::INDEX,
[
'icon' => 'chevron-left',
'class' => 'btn btn-link',
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::INDEX,
[
'icon' => 'chevron-left',
'class' => 'btn btn-link',
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
]
); );




$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_CONTINUE,
[
'class' => 'btn btn-info float-right action-save-continue',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_CONTINUE,
[
'class' => 'btn btn-info float-right action-save-continue',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::DELETE,
[
'icon' => 'trash',
'class' => 'btn btn-outline-danger action-delete',
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::DELETE,
[
'icon' => 'trash',
'class' => 'btn btn-outline-danger action-delete',
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
]
); );
} }


$actions->add(Crud::PAGE_NEW, ActionDefinition::INDEX); $actions->add(Crud::PAGE_NEW, ActionDefinition::INDEX);


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_RETURN,
[
'add_class' => 'float-right',
'icon' => 'check',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_RETURN,
[
'add_class' => 'float-right',
'icon' => 'check',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::INDEX,
[
'icon' => 'chevron-left',
'class' => 'btn btn-link',
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::INDEX,
[
'icon' => 'chevron-left',
'class' => 'btn btn-link',
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
]
); );


$this->actionUpdate( $this->actionUpdate(
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_ADD_ANOTHER,
[
'class' => 'btn btn-info float-right',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'),
]
$actions,
Crud::PAGE_EDIT,
ActionDefinition::SAVE_AND_ADD_ANOTHER,
[
'class' => 'btn btn-info float-right',
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'),
]
); );
} }


{ {
if ($this->isInstanceOf(TranslatableInterface::class)) { if ($this->isInstanceOf(TranslatableInterface::class)) {
$actions->update( $actions->update(
Crud::PAGE_INDEX,
ActionDefinition::EDIT,
function (Action $action) {
$action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig');
Crud::PAGE_INDEX,
ActionDefinition::EDIT,
function (Action $action) {
$action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig');


return $action;
}
return $action;
}
); );
} }
} }
public function handleSortableEntityActions(Actions $actions): void public function handleSortableEntityActions(Actions $actions): void
{ {
if ($this->isInstanceOf(SortableInterface::class)) { if ($this->isInstanceOf(SortableInterface::class)) {
$sortAction = Action::new(ActionDefinition::SORT, $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SORT), 'fa fa-sort')
->linkToCrudAction(ActionDefinition::SORT)
->setCssClass('btn btn-sm btn-success')
->createAsGlobalAction();
$sortAction = Action::new(
ActionDefinition::SORT,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SORT),
'fa fa-sort'
)
->linkToCrudAction(ActionDefinition::SORT)
->setCssClass('btn btn-sm btn-success')
->createAsGlobalAction();


$actions->add(Crud::PAGE_INDEX, $sortAction); $actions->add(Crud::PAGE_INDEX, $sortAction);
} }
} }



public function handleTreeEntityActions(Actions $actions): void public function handleTreeEntityActions(Actions $actions): void
{ {
if ($this->isInstanceOf(TreeInterface::class)) { if ($this->isInstanceOf(TreeInterface::class)) {
$indexChildAction = Action::new( $indexChildAction = Action::new(
ActionDefinition::INDEX_CHILDREN,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_CHILDREN),
'fa fa-list'
ActionDefinition::INDEX_CHILDREN,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_CHILDREN),
'fa fa-list'
) )
->linkToCrudAction(ActionDefinition::INDEX)
->setLabel('')
->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants'))
->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig')
->setCssClass('btn btn-sm btn-success');
->linkToCrudAction(ActionDefinition::INDEX)
->setLabel('')
->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants'))
->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig')
->setCssClass('btn btn-sm btn-success');


$backParentAction = Action::new( $backParentAction = Action::new(
ActionDefinition::INDEX_PARENT,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_PARENT),
'fa fa-chevron-left'
ActionDefinition::INDEX_PARENT,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_PARENT),
'fa fa-chevron-left'
) )
->linkToCrudAction(ActionDefinition::INDEX)
->setCssClass('btn btn-sm btn-info')
->createAsGlobalAction();
->linkToCrudAction(ActionDefinition::INDEX)
->setCssClass('btn btn-sm btn-info')
->createAsGlobalAction();


$actions->add(Crud::PAGE_INDEX, $backParentAction); $actions->add(Crud::PAGE_INDEX, $backParentAction);
$actions->add(Crud::PAGE_INDEX, $indexChildAction); $actions->add(Crud::PAGE_INDEX, $indexChildAction);
{ {
if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) { if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) {
$actions->update( $actions->update(
$crudActionName,
$actionName,
function (Action $action) use ($button) {
if (isset($button['add_class'])) {
$action->addCssClass($button['add_class']);
}

if (isset($button['class'])) {
$action->setCssClass($button['class']);
}
$crudActionName,
$actionName,
function (Action $action) use ($button) {
if (isset($button['add_class'])) {
$action->addCssClass($button['add_class']);
}


if (isset($button['icon'])) {
$action->setIcon('fa fa-' . $button['icon']);
}
if (isset($button['class'])) {
$action->setCssClass($button['class']);
}


if (isset($button['label'])) {
$action->setLabel($button['label']);
}
if (isset($button['icon'])) {
$action->setIcon('fa fa-' . $button['icon']);
}


if (isset($button['dropdown']) && $button['dropdown']) {
$action->addCssClass('in-dropdown');
}
if (isset($button['label'])) {
$action->setLabel($button['label']);
}


if (isset($button['html_attributes']) && $button['html_attributes']) {
$action->setHtmlAttributes($button['html_attributes']);
}
if (isset($button['dropdown']) && $button['dropdown']) {
$action->addCssClass('in-dropdown');
}


return $action;
if (isset($button['html_attributes']) && $button['html_attributes']) {
$action->setHtmlAttributes($button['html_attributes']);
} }

return $action;
}
); );
} }
} }
public function autocompleteFilter(AdminContext $context): JsonResponse public function autocompleteFilter(AdminContext $context): JsonResponse
{ {
$queryBuilder = $this->createIndexQueryBuilder( $queryBuilder = $this->createIndexQueryBuilder(
$context->getSearch(),
$context->getEntity(),
FieldCollection::new([]),
FilterCollection::new()
$context->getSearch(),
$context->getEntity(),
FieldCollection::new([]),
FilterCollection::new()
); );
$autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT); $autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT);


/** @var CrudControllerInterface $controller */ /** @var CrudControllerInterface $controller */
$controller = $this->get(ControllerFactory::class)->getCrudControllerInstance( $controller = $this->get(ControllerFactory::class)->getCrudControllerInstance(
$autocompleteContext[EA::CRUD_CONTROLLER_FQCN],
ActionDefinition::INDEX,
$context->getRequest()
$autocompleteContext[EA::CRUD_CONTROLLER_FQCN],
ActionDefinition::INDEX,
$context->getRequest()
); );
/** @var FieldDto $field */ /** @var FieldDto $field */
$field = FieldCollection::new( $field = FieldCollection::new(
$controller->configureFields($autocompleteContext['originatingPage'])
$controller->configureFields($autocompleteContext['originatingPage'])
)->getByProperty($autocompleteContext['propertyName']); )->getByProperty($autocompleteContext['propertyName']);


$filterManager = $this->get(FilterManager::class); $filterManager = $this->get(FilterManager::class);
{ {
if ($dataInOption) { if ($dataInOption) {
$data = $entity; $data = $entity;
}else{
} else {
$data = null; $data = null;
} }


$options['action'] = $this->get(AdminUrlGenerator::class) $options['action'] = $this->get(AdminUrlGenerator::class)
->setAction($action)
->setController($controller)
->setEntityId($entity->getId())
->generateUrl();
->setAction($action)
->setController($controller)
->setEntityId($entity->getId())
->generateUrl();


return $this->createForm($class, $data, $options); return $this->createForm($class, $data, $options);
} }

+ 2
- 0
Controller/Reminder/ReminderAdminController.php View File

use Lc\CaracoleBundle\Resolver\MerchantResolver; use Lc\CaracoleBundle\Resolver\MerchantResolver;
use Lc\CaracoleBundle\Resolver\SectionResolver; use Lc\CaracoleBundle\Resolver\SectionResolver;
use Lc\SovBundle\Container\Reminder\ReminderContainer; use Lc\SovBundle\Container\Reminder\ReminderContainer;
use Lc\SovBundle\Controller\ControllerTrait;
use Lc\SovBundle\Factory\Reminder\ReminderFactory; use Lc\SovBundle\Factory\Reminder\ReminderFactory;
use Lc\SovBundle\Form\Reminder\ReminderAdminFormType; use Lc\SovBundle\Form\Reminder\ReminderAdminFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;


class ReminderAdminController extends AbstractController class ReminderAdminController extends AbstractController
{ {
use ControllerTrait;


protected EntityManagerInterface $entityManager; protected EntityManagerInterface $entityManager;
protected ReminderContainer $reminderContainer; protected ReminderContainer $reminderContainer;

+ 80
- 104
Controller/Ticket/TicketAdminController.php View File

namespace Lc\SovBundle\Controller\Ticket; namespace Lc\SovBundle\Controller\Ticket;


use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets; use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext; use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Lc\SovBundle\Container\Ticket\TicketContainer;
use Lc\SovBundle\Container\Ticket\TicketMessageContainer; use Lc\SovBundle\Container\Ticket\TicketMessageContainer;
use Lc\SovBundle\Definition\ActionDefinition; use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Factory\Ticket\TicketFactory;
use Lc\SovBundle\Factory\Ticket\TicketFactoryInterface;
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory;
use Lc\SovBundle\Factory\Ticket\TicketMessageFactoryInterface;
use Lc\SovBundle\Form\Ticket\TicketFormType;
use Lc\SovBundle\Form\Ticket\TicketMessageFormType;
use Lc\SovBundle\Event\Ticket\TicketEvent;
use Lc\SovBundle\Form\Ticket\TicketMessageAdminFormType;
use Lc\SovBundle\Form\Ticket\TicketStatusType; use Lc\SovBundle\Form\Ticket\TicketStatusType;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Controller\AbstractAdminController; use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Model\Ticket\TicketModel; use Lc\SovBundle\Model\Ticket\TicketModel;
use Lc\SovBundle\Repository\RepositoryQueryInterface; use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;


abstract class TicketAdminController extends AbstractAdminController abstract class TicketAdminController extends AbstractAdminController
{ {


public function getRepositoryQuery() :RepositoryQueryInterface
public function getRepositoryQuery(): RepositoryQueryInterface
{ {
return $this->getTicketContainer()->getRepositoryQuery(); return $this->getTicketContainer()->getRepositoryQuery();
} }


public function createEntity(string $entityFqcn) public function createEntity(string $entityFqcn)
{ {
return $this->getTicketContainer()->getFactory()->create();
$ticket = $this->getTicketContainer()->getFactory()->create();
return $ticket;
} }


public function configureAssets(Assets $assets): Assets
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
{ {
$assets = parent::configureAssets($assets);
$assets->addWebpackEncoreEntry('sov-ticket');
parent::persistEntity($entityManager, $entityInstance);
$this->getEventDispatcher()->dispatch(new TicketEvent($entityInstance), TicketEvent::NEW_TICKET_EVENT);
}


return $assets;
public function configureCrud(Crud $crud): Crud
{
$crud = parent::configureCrud($crud); // TODO: Change the autogenerated stub
$crud->setDefaultSort(array('updatedAt' => 'DESC'));
return $crud;
} }



public function configureFields(string $pageName): iterable public function configureFields(string $pageName): iterable
{ {
$translatorAdmin = $this->get(TranslatorAdmin::class);
return [
IntegerField::new('id')
->hideOnForm(),
DateField::new('createdAt')->setFormat('short')
->hideOnForm(),
TextField::new('visitorFirstname')
->setTemplatePath('@LcSov/admin/ticket/field/firstname.html.twig')
->hideOnForm(),
TextField::new('visitorLastname')
->setTemplatePath('@LcSov/admin/ticket/field/lastname.html.twig')
->hideOnForm(),
TextField::new('visitorEmail')
->setTemplatePath('@LcSov/admin/ticket/field/email.html.twig')
->hideOnForm(),
AssociationField::new('user')
->hideOnIndex(),
TextField::new('subject'),
TextField::new('lastMessage')
->setTemplatePath('@LcSov/admin/ticket/field/lastmessage.html.twig')
->hideOnForm(),
ChoiceField::new('type')
->autocomplete()
->setChoices(
$translatorAdmin->transChoices($this->get(TicketContainer::class)->getSolver()->getTypeChoices(), 'Ticket', 'type')
),
ChoiceField::new('status')
->autocomplete()
->setChoices(
$translatorAdmin->transChoices($this->get(TicketContainer::class)->getSolver()->getStatusChoices(), 'Ticket', 'status')

)
->setTemplatePath('@LcSov/admin/ticket/field/status.html.twig')
->hideOnForm(),
];
return $this->getTicketContainer()->getFieldDefinition()->getFields($pageName);

} }


public function configureActions(Actions $actions): Actions
public function configureAssets(Assets $assets): Assets
{ {
$actions
->add(Crud::PAGE_INDEX, ActionDefinition::DETAIL)
->remove(Crud::PAGE_INDEX, ActionDefinition::EDIT);
$assets = parent::configureAssets($assets);

$assets->addWebpackEncoreEntry('sov-ticket');


return parent::configureActions($actions);
return $assets;
} }


public function new(AdminContext $context)

public function configureActions(Actions $actions): Actions
{ {
$adminUrlGenerator = $this->get(AdminUrlGenerator::class);
$actions->add(Crud::PAGE_INDEX, ActionDefinition::DETAIL);
$actions = parent::configureActions($actions);
$actions->disable( ActionDefinition::EDIT, ActionDefinition::DUPLICATE);
return $actions;


$ticket = $this->createEntity($context->getEntity()->getFqcn());
}


$form = $this->createForm(TicketFormType::class, $ticket);
public function createIndexRepositoryQuery(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): RepositoryQueryInterface {
$repositoryQuery = parent::createIndexRepositoryQuery(
$searchDto,
$entityDto,
$fields,
$filters
);


$form->handleRequest($context->getRequest());
if ($form->isSubmitted() && $form->isValid()) {
$ticket = $form->getData();
if(!$this->isRepositoryQueryFiltered()){


$this->get(EntityManagerInterface::class)->create($ticket);
$this->get(EntityManagerInterface::class)->flush();
$repositoryQuery->filterByStatus(array(
TicketModel::TICKET_STATUS_OPEN,
TicketModel::TICKET_STATUS_BEING_PROCESSED,
TicketModel::TICKET_STATUS_PROCESSED
));
}


$url = $adminUrlGenerator
->setAction('index')
->generateUrl();
return $repositoryQuery;
}


return $this->redirect($url);
}


return $this->render(
'@LcSov/admin/ticket/new.html.twig',
[
'form' => $form->createView(),
]
);
}


public function detail(AdminContext $context) public function detail(AdminContext $context)
{ {
$ticket = $context->getEntity()->getInstance(); $ticket = $context->getEntity()->getInstance();


$url = $adminUrlGenerator $url = $adminUrlGenerator
->setAction('ticketStatusAction')
->generateUrl();
->setAction('ticketStatusAction')
->generateUrl();


$formTicketStatus = $this->createForm( $formTicketStatus = $this->createForm(
TicketStatusType::class,
$ticket,
[
'action' => $url,
'method' => 'POST',
]
TicketStatusType::class,
$ticket,
[
'action' => $url,
'method' => 'POST',
]
); );


$ticketMessage = $this->get(TicketMessageContainer::class)->getFactory()->create($ticket); $ticketMessage = $this->get(TicketMessageContainer::class)->getFactory()->create($ticket);
$formAddTicketMessage = $this->createForm(TicketMessageFormType::class, $ticketMessage);
$formAddTicketMessage = $this->createForm(TicketMessageAdminFormType::class, $ticketMessage);
$formAddTicketMessage->handleRequest($this->get(RequestStack::class)->getMainRequest()); $formAddTicketMessage->handleRequest($this->get(RequestStack::class)->getMainRequest());


if ($formAddTicketMessage->isSubmitted() && $formAddTicketMessage->isValid()) { if ($formAddTicketMessage->isSubmitted() && $formAddTicketMessage->isValid()) {
$ticketMessage->setAnswerByAdmin(true); $ticketMessage->setAnswerByAdmin(true);
$this->get(EntityManagerInterface::class)->create($ticketMessage); $this->get(EntityManagerInterface::class)->create($ticketMessage);
$this->get(EntityManagerInterface::class)->flush(); $this->get(EntityManagerInterface::class)->flush();
$this->getEventDispatcher()->dispatch(new TicketEvent($ticket), TicketEvent::NEW_MESSAGE_EVENT);

return $this->redirect($this->generateEaUrl());
} }


return $this->render( return $this->render(
'@LcSov/admin/ticket/detail.html.twig',
[
'form_ticket_status' => $formTicketStatus->createView(),
'form_add_ticket_message' => $formAddTicketMessage->createView(),
'ticket' => $ticket,
]
'@LcSov/admin/ticket/detail.html.twig',
[
'form_ticket_status' => $formTicketStatus->createView(),
'form_add_ticket_message' => $formAddTicketMessage->createView(),
'ticket' => $ticket,
]
); );
} }




public function ticketStatusAction()

public function ticketStatusAction(AdminContext $context, EntityManagerInterface $entityManager)
{ {
$request = $this->get('request')->getMasterRequest();
$ticket = $request->attributes->get('easyadmin_context')->getEntity()->getInstance();
$ticket = $context->getEntity()->getInstance();


$formTicketStatusForm = $this->createForm(TicketStatusType::class, $ticket); $formTicketStatusForm = $this->createForm(TicketStatusType::class, $ticket);
$formTicketStatusForm->handleRequest($request);
$formTicketStatusForm->handleRequest($context->getRequest());


$success = false; $success = false;
if ($formTicketStatusForm->isSubmitted() && $formTicketStatusForm->isValid()) { if ($formTicketStatusForm->isSubmitted() && $formTicketStatusForm->isValid()) {
$this->get('em')->persist($ticket);
$this->get('em')->flush();

$entityManager->update($ticket);
$entityManager->flush();
$success = true; $success = true;
} }



+ 39
- 8
Controller/User/UserAdminController.php View File



namespace Lc\SovBundle\Controller\User; namespace Lc\SovBundle\Controller\User;


use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField; use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Container\User\UserContainer; use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Controller\AbstractAdminController; use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Definition\RolesDefinition; use Lc\SovBundle\Definition\RolesDefinition;
use Lc\SovBundle\Definition\RolesDefinitionInterface; use Lc\SovBundle\Definition\RolesDefinitionInterface;
use Lc\SovBundle\Doctrine\EntityManager; use Lc\SovBundle\Doctrine\EntityManager;
{ {
protected RolesDefinitionInterface $rolesDefinition; protected RolesDefinitionInterface $rolesDefinition;


public function __construct(
SessionInterface $session,
RequestStack $request,
EntityManager $em,
TranslatorAdmin $translatorAdmin,
RolesDefinitionInterface $rolesDefinition
) {
$this->rolesDefinition = $rolesDefinition;

public function buildIndexActions(Actions $actions): void
{
parent::buildIndexActions($actions); // TODO: Change the autogenerated stub

$actions->add(Crud::PAGE_INDEX, $this->getSwitchUserAction());
}

public function getSwitchUserAction(): Action
{
$switchAction = Action::new(
ActionDefinition::SWITCH_USER,
$this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SWITCH_USER),
'fa fa-fw fa-user-secret'
)
->linkToCrudAction(ActionDefinition::SWITCH_USER)
->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SWITCH_USER))
->setCssClass('in-dropdown text-info action-confirm action_switch');

return $switchAction;
}

public function overrideEntitiesActions(?EntityCollection $entities): void
{
parent::overrideEntitiesActions($entities); // TODO: Change the autogenerated stub
foreach ($entities as $entity) {
foreach ($entity->getActions() as $action){
if($action->getName() == ActionDefinition::SWITCH_USER){
$url = $this->generateUrl($this->getParameter('lc_sov.homepage_route'), array('_switch_user' => $entity->getInstance()->getEmail()));
$action->setLinkUrl($url);
}
}

}
} }


public function configureFields(string $pageName): iterable public function configureFields(string $pageName): iterable

+ 3
- 0
Definition/ActionDefinition.php View File

public const SAVE_AND_ADD_ANOTHER = 'saveAndAddAnother'; public const SAVE_AND_ADD_ANOTHER = 'saveAndAddAnother';
public const SAVE_AND_CONTINUE = 'saveAndContinue'; public const SAVE_AND_CONTINUE = 'saveAndContinue';
public const SAVE_AND_RETURN = 'saveAndReturn'; public const SAVE_AND_RETURN = 'saveAndReturn';
public const SWITCH_USER = 'switchUser';
public const WRITE_TO_USER = 'writeToUser';

} }

+ 17
- 2
Definition/Field/AbstractFieldDefinition.php View File

namespace Lc\SovBundle\Definition\Field; namespace Lc\SovBundle\Definition\Field;


use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField; use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
->hideOnIndex(), ->hideOnIndex(),
'devAlias' => TextField::new('devAlias')->hideOnIndex(), 'devAlias' => TextField::new('devAlias')->hideOnIndex(),
'status' => StatusField::new('status')->setSortable(true), 'status' => StatusField::new('status')->setSortable(true),
'createdAt' => DateTimeField::new('createdAt')->setSortable(true),
'updatedAt' => DateTimeField::new('updatedAt')->setSortable(true),
]; ];
} }


throw new \Exception($method . ' n\'existe pas '); throw new \Exception($method . ' n\'existe pas ');
} }


$fieldPanel = FormField::addPanel($panel);
$method = 'panel'.ucfirst($panel).'CustomOptions';
if(method_exists($this, $method)) {
foreach ($this->$method() as $customOptionKey => $customOptionValue){
$fieldPanel->setCustomOption($customOptionKey, $customOptionValue);
}

}

return array_merge( return array_merge(
['panel_' . $panel => FormField::addPanel($panel)],
[
'panel_' . $panel => $fieldPanel

],
$this->buildFieldArray($panelFieldArray) $this->buildFieldArray($panelFieldArray)
); );
} }


}
}

+ 2
- 2
Definition/Field/Site/NewsFieldDefinition.php View File

use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField; use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField; use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition; use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\SovBundle\Field\BooleanField; use Lc\SovBundle\Field\BooleanField;
use Lc\SovBundle\Field\CKEditorField;
use Lc\SovBundle\Field\ImageManagerField; use Lc\SovBundle\Field\ImageManagerField;


class NewsFieldDefinition extends AbstractFieldDefinition class NewsFieldDefinition extends AbstractFieldDefinition
'newsletter' => AssociationField::new('newsletter')->setSortable(true), 'newsletter' => AssociationField::new('newsletter')->setSortable(true),
'image' => ImageManagerField::new('image'), 'image' => ImageManagerField::new('image'),
'position' => NumberField::new('position'), 'position' => NumberField::new('position'),
'description' => TextEditorField::new('description'),
'description' => CKEditorField::new('description'),
'isSent' => BooleanField::new('isSent')->setSortable(true), 'isSent' => BooleanField::new('isSent')->setSortable(true),
]; ];
} }

+ 118
- 0
Definition/Field/Ticket/TicketFieldDefinition.php View File

<?php

namespace Lc\SovBundle\Definition\Field\Ticket;

use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Field\Filter\Ticket\TicketEmailFilter;
use Lc\SovBundle\Field\Filter\Ticket\TicketFirstnameFilter;
use Lc\SovBundle\Field\Filter\Ticket\TicketLastnameFilter;
use Lc\SovBundle\Form\Ticket\TicketMessageAdminFormType;
use Lc\SovBundle\Solver\Ticket\TicketSolver;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Form\Ticket\TicketMessageType;
use Lc\SovBundle\Translation\TranslatorAdmin;

class TicketFieldDefinition extends AbstractFieldDefinition
{
public function __construct(TranslatorAdmin $translatorAdmin)
{
parent::__construct($translatorAdmin);
}

public function configureIndex(): array
{
return [
'id',
'createdAt',
'visitorFirstname',
'visitorLastname',
'visitorEmail',
'subject',
'updatedAt',
'type',
'status'
];
}

public function configureForm(): array
{
return [
'user',
'type',
'subject',
'ticketMessages'
];
}

public function configurePanels(): array
{
return [];
}

public function configureFields(): array
{
return [
'id' => IdField::new('id')
->setSortable(true)
->hideOnForm(),
'createdAt' => DateTimeField::new('createdAt')
->setSortable(true)
->hideOnForm(),
'visitorFirstname' => TextField::new('visitorFirstname')
->setTemplatePath('@LcSov/admin/ticket/field/firstname.html.twig')
->setCustomOption('filter_fqcn', TicketFirstnameFilter::class)
->setSortable(true)
->hideOnForm(),
'visitorLastname' => TextField::new('visitorLastname')
->setTemplatePath('@LcSov/admin/ticket/field/lastname.html.twig')
->setCustomOption('filter_fqcn', TicketLastnameFilter::class)
->setSortable(true)
->hideOnForm(),
'visitorEmail' => TextField::new('visitorEmail')
->setTemplatePath('@LcSov/admin/ticket/field/email.html.twig')
->setCustomOption('filter_fqcn', TicketEmailFilter::class)
->setSortable(true)
->hideOnForm(),
'user' => AssociationField::new('user')
->hideOnIndex(),
'subject' => TextField::new('subject')
->setSortable(true),
'updatedAt' => DateTimeField::new('updatedAt')
->setTemplatePath('@LcSov/admin/ticket/field/lastmessage.html.twig')
->setSortable(true)
->hideOnForm(),
'type' => ChoiceField::new('type')
->autocomplete()
->setSortable(true)
->setChoices(
$this->translatorAdmin->transChoices(
TicketSolver::getTypeChoices(),
'Ticket',
'type'
)
),
'status' => ChoiceField::new('status')
->autocomplete()
->setSortable(true)
->setChoices(
$this->translatorAdmin->transChoices(
TicketSolver::getStatusChoices(),
'Ticket',
'status'
)
)
->setTemplatePath('@LcSov/admin/ticket/field/status.html.twig'),

'ticketMessages' => CollectionField::new('ticketMessages')
->setFormTypeOption('entry_type', TicketMessageAdminFormType::class)
->setFormTypeOption('allow_add', false)
->setFormTypeOption('allow_delete', false)
];
}

}

+ 15
- 2
Definition/Field/User/UserFieldDefinition.php View File

use Lc\CaracoleBundle\Field\AssociationField; use Lc\CaracoleBundle\Field\AssociationField;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition; use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\SovBundle\Definition\RolesDefinition; use Lc\SovBundle\Definition\RolesDefinition;
use Lc\SovBundle\Solver\Ticket\TicketSolver;
use Lc\SovBundle\Solver\User\UserSolver; use Lc\SovBundle\Solver\User\UserSolver;
use Lc\SovBundle\Translation\TranslatorAdmin; use Lc\SovBundle\Translation\TranslatorAdmin;


'email', 'email',
'phone', 'phone',
'birthdate', 'birthdate',
'groupUsers'
'groupUsers',
'ticketTypesNotification'
]; ];
} }


'firstname' => TextField::new('firstname')->setSortable(true), 'firstname' => TextField::new('firstname')->setSortable(true),
'email' => TextField::new('email')->setSortable(true), 'email' => TextField::new('email')->setSortable(true),
'phone' => TextField::new('phone')->setSortable(true), 'phone' => TextField::new('phone')->setSortable(true),
'birthdate' => DateField::new('birthdate')->setSortable(true),
'birthdate' => DateField::new('birthdate')
->setFormTypeOption('required', false)
->setSortable(true),
'groupUsers' => AssociationField::new('groupUsers')->setSortable(true), 'groupUsers' => AssociationField::new('groupUsers')->setSortable(true),
'ticketTypesNotification' => ChoiceField::new('ticketTypesNotification')
->setSortable(true)
->setFormTypeOption('expanded', false)
->setFormTypeOption('multiple', true)
->setChoices($this->translatorAdmin->transChoices(
TicketSolver::getTypeChoices(),
'Ticket',
'type'
)),
'roles' => ChoiceField::new('roles') 'roles' => ChoiceField::new('roles')
->allowMultipleChoices() ->allowMultipleChoices()
->autocomplete() ->autocomplete()

+ 0
- 17
Definition/SiteSettingDefinition.php View File

'name' => self::SETTING_MAINTENANCE_IP_AUTHORIZED, 'name' => self::SETTING_MAINTENANCE_IP_AUTHORIZED,
] ]
); );


// email
$this->addSettingText(
[
'category' => self::CATEGORY_EMAIL,
'name' => self::SETTING_EMAIL_FROM,
]
);

$this->addSettingText(
[
'category' => self::CATEGORY_EMAIL,
'name' => self::SETTING_EMAIL_FROM_NAME,
]
);
} }


public function getCategories() public function getCategories()
{ {
return [ return [
self::CATEGORY_GENERAL, self::CATEGORY_GENERAL,
self::CATEGORY_EMAIL
]; ];
} }



+ 30
- 0
Event/Ticket/TicketEvent.php View File

<?php

namespace Lc\SovBundle\Event\Ticket;

use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Symfony\Contracts\EventDispatcher\Event;

/**
* class EntityEvent.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class TicketEvent extends Event
{
const NEW_TICKET_EVENT = 'ticket_event.new_ticket';
const NEW_MESSAGE_EVENT = 'ticket_event.new_message';

protected TicketInterface $ticket;

public function __construct(TicketInterface $ticket)
{
$this->ticket = $ticket;
}

public function getTicket(): TicketInterface
{
return $this->ticket;
}
}

+ 0
- 1
EventSubscriber/SiteSettingEventSubscriber.php View File

{ {
return $this->siteStore->getOneByDevAlias('default'); return $this->siteStore->getOneByDevAlias('default');
} }

} }

+ 138
- 0
EventSubscriber/Ticket/SendNotificationTicketEventSubscriber.php View File

<?php

namespace Lc\SovBundle\EventSubscriber\Ticket;

use Lc\SovBundle\Event\EntityManager\EntityManagerEvent;
use Lc\SovBundle\Event\Ticket\TicketEvent;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
use Lc\SovBundle\Notification\MailMailjetNotification;
use Lc\SovBundle\Repository\User\UserStore;
use Lc\SovBundle\Solver\Ticket\TicketSolver;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class SendNotificationTicketEventSubscriber implements EventSubscriberInterface
{
protected MailMailjetNotification $mailMailjetNotification;
protected UserStore $userStore;
protected AuthorizationCheckerInterface $authorizationChecker;
protected TicketSolver $ticketSolver;

public function __construct(
MailMailjetNotification $mailMailjetNotification,
UserStore $userStore,
AuthorizationCheckerInterface $authorizationChecker,
TicketSolver $ticketSolver
) {
$this->mailMailjetNotification = $mailMailjetNotification;
$this->userStore = $userStore;
$this->authorizationChecker = $authorizationChecker;
$this->ticketSolver = $ticketSolver;
}

public static function getSubscribedEvents()
{
return [
TicketEvent::NEW_MESSAGE_EVENT => ['sendNotificationAfterNewMessage'],
TicketEvent::NEW_TICKET_EVENT => ['sendNotificationAfterNewTicket'],
];
}


public function sendNotificationAfterNewTicket(TicketEvent $ticketEvent)
{
$ticket = $ticketEvent->getTicket();
$lastMessage = $this->ticketSolver->getLastMessage($ticket);
if ($ticket->getUser()) {
$firstname = $ticket->getUser()->getFirstname();
$email = $ticket->getUser()->getEmail();
} else {
$firstname = $ticket->getVisitorFirstname();
$email = $ticket->getVisitorEmail();
}

if ($lastMessage->getAnswerByAdmin()) {
// envoi email au client
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Vous avez reçu un nouveau message',
MailMailjetNotification::TO_EMAIL => $email,
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new-by-admin',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
} else {
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Nouvelle demande',
MailMailjetNotification::TO_EMAIL => $email,
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
}

$this->notifyUser($ticket);
}

public function sendNotificationAfterNewMessage(TicketEvent $ticketEvent)
{
$ticket = $ticketEvent->getTicket();
$lastMessage = $this->ticketSolver->getLastMessage($ticket);
if ($ticket->getUser()) {
$firstname = $ticket->getUser()->getFirstname();
$email = $ticket->getUser()->getEmail();
} else {
$firstname = $ticket->getVisitorFirstname();
$email = $ticket->getVisitorEmail();
}

if ($lastMessage->getAnswerByAdmin()) {
// envoi email au client
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Réponse à votre demande',
MailMailjetNotification::TO_EMAIL => $email,
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-response',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
}
$this->notifyUser($ticket);
}

protected function notifyUser(TicketInterface $ticket): void
{
// notifyAdmin
$usersToNotify = $this->userStore->getByTicketTypesNotification($ticket->getType());

foreach ($usersToNotify as $userToNotify) {
if ($this->authorizationChecker->isGranted('ROLE_ADMIN', $userToNotify)) {
$this->mailMailjetNotification->send(
[
MailMailjetNotification::SUBJECT => 'Nouveau ticket sur Place du Local',
MailMailjetNotification::TO_EMAIL => $userToNotify->getEmail(),
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-notification',
MailMailjetNotification::CONTENT_DATA => [
'firstname' => $userToNotify->getFirstname(),
'ticket' => $ticket,
'ticketMessage' => $ticket->getTicketMessages()[0],
],
]
);
}
}
}


}

+ 2
- 0
Factory/Site/NewsFactory.php View File

{ {
$news = new News(); $news = new News();


$news->setStatus(1);

return $news; return $news;
} }



+ 2
- 0
Factory/Site/PageFactory.php View File

{ {
$page = new Page(); $page = new Page();


$page->setStatus(1);

return $page; return $page;
} }
} }

+ 2
- 0
Factory/User/GroupUserFactory.php View File

{ {
$groupUser = new GroupUser(); $groupUser = new GroupUser();


$groupUser->setStatus(1);

return $groupUser; return $groupUser;
} }
} }

+ 1
- 1
Field/BooleanField.php View File

return (new self()) return (new self())
->setProperty($propertyName) ->setProperty($propertyName)
->setLabel($label) ->setLabel($label)
->setTemplatePath('@LcSov/adminlte/crud/field/boolean.html.twig')
->setTemplatePath('@LcSov/adminlte/crud/field/toggle.html.twig')
->setFormType(CheckboxType::class); ->setFormType(CheckboxType::class);
} }



+ 1
- 14
Field/Filter/ChoiceFilter.php View File

{ {
$fieldProperty = $this->getFieldProperty($fieldDto); $fieldProperty = $this->getFieldProperty($fieldDto);
if ($filteredValue !== null) { if ($filteredValue !== null) {
// if ($this->isRelationField($fieldProperty)) {
// $aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty);
// if (array_search($aliasRelation, $repositoryQuery->getAllAliases()) === false) {
// $repositoryQuery->innerJoin('entity.'.$aliasRelation, $aliasRelation);
// }
// $repositoryQuery->andWhere(
// $fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).''
// );
// $repositoryQuery->setParameter(
// $this->getFieldPropertySnake($fieldProperty),
// '%'.$filteredValue.'%'
// );
// } else {
$repositoryQuery->andWhere( $repositoryQuery->andWhere(
'.'.$fieldProperty.' LIKE :'.$fieldProperty.'' '.'.$fieldProperty.' LIKE :'.$fieldProperty.''
); );
$repositoryQuery->setParameter($fieldProperty, '%'.$filteredValue.'%');
$repositoryQuery->setParameter($fieldProperty, $filteredValue);


} }
} }

+ 11
- 12
Field/Filter/FilterManager.php View File

class FilterManager class FilterManager
{ {
protected $em; protected $em;
protected bool $isFiltered = false;


use FilterTrait; use FilterTrait;


} }




public function handleFiltersForm(RepositoryQueryInterface $repositoryQuery, Form $filtersForm, $fields, EntityDto $entityDto)
public function handleFiltersForm(RepositoryQueryInterface $repositoryQuery, Form $filtersForm, $fields, EntityDto $entityDto):bool
{ {


foreach ($fields as $field) { foreach ($fields as $field) {
$fieldDto->getProperty(), $fieldDto->getProperty(),
'dateEnd' 'dateEnd'
); );
if($filteredValue['dateStart'] || $filteredValue['dateEnd']){
$this->isFiltered = true;
}
} else { } else {
$filteredValue['value'] = $this->getFilteredValue( $filteredValue['value'] = $this->getFilteredValue(
$filtersForm, $filtersForm,
$entityDto->getFqcn(), $entityDto->getFqcn(),
$fieldDto->getProperty() $fieldDto->getProperty()
); );
if($filteredValue['value'] ){
$this->isFiltered = true;
}
} }

$this->applyFilter($repositoryQuery, $fieldDto, $filteredValue); $this->applyFilter($repositoryQuery, $fieldDto, $filteredValue);
} }
} }
} }
return $this->isFiltered;
} }




$customFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']); $customFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
} else { } else {


switch ($this->guessFormType($fieldDto)) {
switch ($fieldDto->getFormType()) {


case CheckboxType::class: case CheckboxType::class:
$checkboxFilter = new CheckboxFilter(); $checkboxFilter = new CheckboxFilter();
} }
} }



protected function guessFormType(FieldDto $fieldDto)
{
if ($fieldDto->getCustomOption('filter_type')) {
return $fieldDto->getCustomOption('filter_type');
} else {
return $fieldDto->getFormType();
}

}
} }

+ 3
- 3
Field/Filter/FilterTrait.php View File

{ {
$property = $fieldDto->getProperty(); $property = $fieldDto->getProperty();
//TODO pas forcément utile, à discuter //TODO pas forcément utile, à discuter
if ($fieldDto->getCustomOption('filter_on')) {
$property = $property . '.' . $fieldDto->getCustomOption('filter_on');
}
// if ($fieldDto->getCustomOption('filter_on')) {
// $property = $property . '.' . $fieldDto->getCustomOption('filter_on');
// }
return $property; return $property;
} }



+ 38
- 0
Field/Filter/Ticket/TicketEmailFilter.php View File

<?php

namespace Lc\SovBundle\Field\Filter\Ticket;

use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Field\Filter\AssociationFilter;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @author La clic ! <contact@laclic.fr>
*/
class TicketEmailFilter extends AssociationFilter
{
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$builder->add(
$fieldDto->getProperty(),
TextType::class,
array(
'required' => false,
'attr' => array(
'class' => ' input-sm',
'form' => 'filters-form',
),
)
);
}

public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null)
{
if ($filteredValue !== null) {
$repositoryQuery->filterByEmail($filteredValue);
}
}

}

+ 38
- 0
Field/Filter/Ticket/TicketFirstnameFilter.php View File

<?php

namespace Lc\SovBundle\Field\Filter\Ticket;

use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Field\Filter\AssociationFilter;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @author La clic ! <contact@laclic.fr>
*/
class TicketFirstnameFilter extends AssociationFilter
{
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$builder->add(
$fieldDto->getProperty(),
TextType::class,
array(
'required' => false,
'attr' => array(
'class' => ' input-sm',
'form' => 'filters-form',
),
)
);
}

public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null)
{
if ($filteredValue !== null) {
$repositoryQuery->filterByFirstname($filteredValue);
}
}

}

+ 38
- 0
Field/Filter/Ticket/TicketLastnameFilter.php View File

<?php

namespace Lc\SovBundle\Field\Filter\Ticket;

use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Field\Filter\AssociationFilter;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @author La clic ! <contact@laclic.fr>
*/
class TicketLastnameFilter extends AssociationFilter
{
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$builder->add(
$fieldDto->getProperty(),
TextType::class,
array(
'required' => false,
'attr' => array(
'class' => ' input-sm',
'form' => 'filters-form',
),
)
);
}

public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null)
{
if ($filteredValue !== null) {
$repositoryQuery->filterByLastname($filteredValue);
}
}

}

+ 8
- 11
Form/Ticket/TicketFormType.php View File

{ {
protected EntityManager $entityManager; protected EntityManager $entityManager;
protected TranslatorAdmin $translatorAdmin; protected TranslatorAdmin $translatorAdmin;
protected TicketSolver $ticketSolver;


public function __construct( public function __construct(
EntityManager $entityManager, EntityManager $entityManager,
TranslatorAdmin $translatorAdmin,
TicketSolver $ticketSolver
TranslatorAdmin $translatorAdmin
) { ) {
$this->entityManager = $entityManager; $this->entityManager = $entityManager;
$this->translatorAdmin = $translatorAdmin; $this->translatorAdmin = $translatorAdmin;
$this->ticketSolver = $ticketSolver;
} }


public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
] ]
); );


$builder->add(
'subject',
TextType::class
);

$builder->add( $builder->add(
'type', 'type',
ChoiceType::class, ChoiceType::class,
[ [
'label' => 'Type', 'label' => 'Type',
'choices' => $this->translatorAdmin->transChoices( 'choices' => $this->translatorAdmin->transChoices(
$this->ticketSolver->getTypeChoices(),
TicketSolver::getTypeChoices(),
'Ticket', 'Ticket',
'type' 'type'
), ),
] ]
); );


$builder->add(
'subject',
TextType::class
);

$builder->add( $builder->add(
'ticketMessages', 'ticketMessages',
CollectionType::class, CollectionType::class,
] ]
); );
} }
}
}

Form/Ticket/TicketMessageFormType.php → Form/Ticket/TicketMessageAdminFormType.php View File

use Lc\SovBundle\Model\Ticket\TicketMessageInterface; use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
use Lc\SovBundle\Translation\TranslatorAdmin; use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;


class TicketMessageFormType extends AbstractType
class TicketMessageAdminFormType extends AbstractType
{ {
protected $em; protected $em;
protected $translatorAdmin; protected $translatorAdmin;
'required' => true 'required' => true
] ]
); );

$builder->add( $builder->add(
'submit',
SubmitType::class,
[
'label' => $this->translatorAdmin->transAction('send')
]
'answerByAdmin',
HiddenType::class,
[
'data' => 1
]
); );
} }



+ 9
- 10
Form/Ticket/TicketMessageType.php View File



namespace Lc\SovBundle\Form\Ticket; namespace Lc\SovBundle\Form\Ticket;


use App\Entity\Address;
use App\Entity\OrderShop;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Lc\ShopBundle\Model\Ticket;
use Lc\ShopBundle\Services\UtilsManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; 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\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\File;


class TicketMessageType extends AbstractType class TicketMessageType extends AbstractType
{ {
protected EntityManagerInterface $entityManager;

public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}


public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
'label' => 'entity.TicketMessage.fields.closeTicket', 'label' => 'entity.TicketMessage.fields.closeTicket',
'translation_domain' => 'admin', 'translation_domain' => 'admin',
'required' => false, 'required' => false,
'mapped' => false,
]); ]);
} }


public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults([ $resolver->setDefaults([
// Configure your form options here
'data_class' => $this->entityManager->getEntityName(TicketMessageInterface::class),
]); ]);
} }
} }

+ 1
- 2
Model/Ticket/TicketMessageModel.php View File

{ {
use StatusTrait; use StatusTrait;



/** /**
* @ORM\Column(type="text") * @ORM\Column(type="text")
*/ */


public function __toString() public function __toString()
{ {
return $this->message;
return ''.$this->message;
} }


public function getMessage(): ?string public function getMessage(): ?string

+ 1
- 2
Model/Ticket/TicketModel.php View File



const TICKET_STATUS_OPEN = 'open'; const TICKET_STATUS_OPEN = 'open';
const TICKET_STATUS_BEING_PROCESSED = 'being-processed'; const TICKET_STATUS_BEING_PROCESSED = 'being-processed';
const TICKET_STATUS_PROCESSED = 'processed';
const TICKET_STATUS_CLOSED = 'closed'; const TICKET_STATUS_CLOSED = 'closed';


/** /**
return $this; return $this;
} }



public function getStatus(): ?string public function getStatus(): ?string
{ {
return $this->status; return $this->status;
return $this; return $this;
} }



public function getSubject(): ?string public function getSubject(): ?string
{ {
return $this->subject; return $this->subject;

+ 1
- 1
Model/User/UserModel.php View File

return $this->birthdate; return $this->birthdate;
} }


public function setBirthdate(\DateTimeInterface $birthdate): self
public function setBirthdate(?\DateTimeInterface $birthdate): self
{ {
$this->birthdate = $birthdate; $this->birthdate = $birthdate;



+ 1
- 3
Repository/AbstractRepositoryQuery.php View File



public function filterByOldUrl(string $oldUrl): self public function filterByOldUrl(string $oldUrl): self
{ {
// @TODO : ne fonctionne pas, utilisation de LIKE à la place ?
//return $this->andWhere(':oldUrl IN (.oldUrls)')->setParameter('oldUrl', $oldUrl);
return $this->andWhere(':oldUrl LIKE .oldUrls')->setParameter('oldUrl', $oldUrl);
return $this->andWhere('.oldUrls LIKE :oldUrl')->setParameter('oldUrl', '%'.$oldUrl.'%');
} }


/* /*

+ 41
- 0
Repository/Ticket/TicketRepositoryQuery.php View File



class TicketRepositoryQuery extends AbstractRepositoryQuery implements TicketRepositoryQueryInterface class TicketRepositoryQuery extends AbstractRepositoryQuery implements TicketRepositoryQueryInterface
{ {

protected $isJoinUser = false;

public function __construct(TicketRepository $repository, PaginatorInterface $paginator) public function __construct(TicketRepository $repository, PaginatorInterface $paginator)
{ {
parent::__construct($repository, 'r', $paginator); parent::__construct($repository, 'r', $paginator);
->setParameter('user', $user); ->setParameter('user', $user);
} }


public function joinUser(): self
{
if (!$this->isJoinUser) {
$this->isJoinUser = true;

return $this
->leftJoin('.user', 'user');
}
return $this;
}

public function filterByStatus($statusArray): self public function filterByStatus($statusArray): self
{ {
return $this return $this
->setParameter('status', $statusArray); ->setParameter('status', $statusArray);
} }


public function filterByFirstname(string $firstname)
{
$this->joinUser();

return $this
->andWhere('.visitorFirstname LIKE :firstname OR u.firstname LIKE :firstname')
->setParameter('firstname', '%'.$firstname.'%');
}

public function filterByLastname(string $lastname)
{
$this->joinUser();

return $this
->andWhere('.visitorLastname LIKE :lastname OR u.lastname LIKE :lastname')
->setParameter('lastname', '%'.$lastname.'%');
}

public function filterByEmail(string $email)
{
$this->joinUser();

return $this
->andWhere('.visitorEmail LIKE :email OR u.email LIKE :email')
->setParameter('email', '%'.$email.'%');
}

public function selectCount(): self public function selectCount(): self
{ {
return $this return $this

+ 13
- 0
Repository/User/GroupUserRepositoryQuery.php View File

{ {
parent::__construct($repository, 'r', $paginator); parent::__construct($repository, 'r', $paginator);
} }

protected $isJoinUsers = false;

public function joinUsers(): self
{

if (!$this->isJoinUsers) {
$this->isJoinUsers = true;
return $this
->innerJoin('.users', 'user');
}
return $this;
}
} }

+ 1
- 0
Repository/User/GroupUserStore.php View File



public function relationsDefault(RepositoryQueryInterface $query): RepositoryQueryInterface public function relationsDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
{ {
$query->joinUsers();
return $query; return $query;
} }
} }

+ 16
- 0
Repository/User/UserRepositoryQuery.php View File

parent::__construct($repository, 'r', $paginator); parent::__construct($repository, 'r', $paginator);
} }


protected $isJoinGroupUsers = false;

public function joinGroupUsers($addSelect = true): self
{
if (!$this->isJoinGroupUsers) {
$this->isJoinGroupUsers = true;

$this->innerJoin('.groupUsers', 'groupUser');
if($addSelect){
$this->addSelect('groupUser');
}
}
return $this;
}


public function filterByNewsletter(Newsletter $newsletter): self public function filterByNewsletter(Newsletter $newsletter): self
{ {
return $this return $this

+ 10
- 0
Resources/assets/app/adminlte/index/index.scss View File

white-space: normal; white-space: normal;
} }
} }


table.fixedHeader-floating{margin-top: 0px !important;}
table th.sorting_asc, table th.sorting_desc{border-top:2px solid var(--success);}
.card-body table th.filtered{border-top:2px solid var(--primary);}
/*.card-body table.lc-table-list th{border-top:3px solid var(--success);}*/
table th.filtered{border-top:2px solid var(--primary);}
.card-body table th.sorted, table th.sorting_asc, table th.sorting_desc{border-top:2px solid var(--success);}
.card-body table th.sorted.filtered{border-top:0px; position: relative;}
.card-body table th.sorted.filtered:after{ content: ''; height: 2px; position: absolute; left: 0; width: 100%; right: 0; top: -1px; background: linear-gradient(to right, var(--success) 0%, var(--success) 50%, var(--primary) 50%, var(--primary) 100%);}

+ 1
- 2
Resources/assets/app/adminlte/sort/sort.js View File



// Replace '__name__' in the prototype's HTML to // Replace '__name__' in the prototype's HTML to
$(li).find('div:last-child').remove(); $(li).find('div:last-child').remove();

$(li).append(newForm);
$(li).find('td:first').append('<div class="hidden">'+newForm+'</div>');
$(li).find('#form_entities_' + index + '_id').val($(li).data('id')); $(li).find('#form_entities_' + index + '_id').val($(li).data('id'));
/* if ($('.sov-sortable').data('parent-position') !== '') { /* if ($('.sov-sortable').data('parent-position') !== '') {
//Ajout d'un 0 initial pour les nuémros <10 //Ajout d'un 0 initial pour les nuémros <10

+ 5
- 4
Resources/translations/admin.fr.yaml View File

account: Mon compte account: Mon compte
account_profile: Informations personnelles account_profile: Informations personnelles
account_password: Mot de passe account_password: Mot de passe
tickets: Tickets
tickets: Tickets <span class="float-right badge badge-info">%total_ticket_open%</span>
setting_global: Global setting_global: Global


title: title:
label: Ticket label: Ticket
label_plurial: Tickets label_plurial: Tickets
fields: fields:
visitorFirstName: Nom
visitorLastName: Prénom
visitorFirstname: Nom
visitorLastname: Prénom
visitorEmail: E-mail visitorEmail: E-mail
subject: Sujet subject: Sujet
type: Type type: Type
open: Ouvert open: Ouvert
being-processed: En attente being-processed: En attente
closed: Fermé closed: Fermé
ticketMessages: Message
TicketModel: TicketModel:
fields: fields:
open: Ouvert open: Ouvert
default: default:
fields: fields:
id: Id id: Id
createdAt: Créé à
createdAt: Créé le
user: Utilisateur user: Utilisateur
firstname: Prénom firstname: Prénom
lastname: Nom lastname: Nom

+ 3
- 0
Resources/views/admin/ticket/detail.html.twig View File

<div class="col-12"> <div class="col-12">
{{ form_row(form_add_ticket_message.message) }} {{ form_row(form_add_ticket_message.message) }}
</div> </div>
<div class="col-12 text-right">
<button type="submit" class="btn btn-primary text-right">{{ 'send'|sov_trans_admin_action }}</button>
</div>
</div> </div>
{{ form_end(form_add_ticket_message) }} {{ form_end(form_add_ticket_message) }}
</div> </div>

+ 32
- 7
Resources/views/admin/ticket/field/lastmessage.html.twig View File

{#{% set ticketMessage = entity.instance.getLastMessage() %}#}
{#{% if ticketMessage.answerByAdmin != true %}#}
{# <span class="badge badge-danger">#}
{# New#}
{# </span>#}
{#{% endif %}#}
{#{{ ticketMessage.createdAt|date('d/m/Y H:i') }} par {{ ticketMessage.createdBy }} {{ ticketMessage.message }}#}
{% if item is not defined %}
{% set item = entity.instance %}
{% endif %}
{% set ticketMessage = ticket_container.solver.getLastMessage(item) %}
{% if ticketMessage.answerByAdmin != true %}
<span class="badge badge-danger">
New
</span>
{% endif %}

{{ ticketMessage.createdAt|date('d/m/Y H:i') }} par

{% if ticketMessage.answerByAdmin %}
Équipe
{% else %}
Client
{% endif %}


{# {% set ticket = entity.instance %} #}
{# {% if ticket.ticketMessages %} #}
{# {% for message in ticket.ticketMessages %} #}
{# {% if loop.last %} #}
{# {% if message.answerByAdmin %} #}
{# Équipe #}
{# {% else %} #}
{# Client #}
{# {% endif %} #}
{# {% endif %} #}
{# {% endfor %} #}
{# {% endif %} #}


+ 2
- 0
Resources/views/admin/ticket/field/status.html.twig View File

{{ macro.badge_success(status|sov_trans_admin_choice('status','Ticket')) }} {{ macro.badge_success(status|sov_trans_admin_choice('status','Ticket')) }}
{% elseif status == 'being-processed' %} {% elseif status == 'being-processed' %}
{{ macro.badge_warning(status|sov_trans_admin_choice('status','Ticket')) }} {{ macro.badge_warning(status|sov_trans_admin_choice('status','Ticket')) }}
{% elseif status == 'processed' %}
{{ macro.badge_info(status|sov_trans_admin_choice('status','Ticket')) }}
{% elseif status == 'closed' %} {% elseif status == 'closed' %}
{{ macro.badge_danger(status|sov_trans_admin_choice('status','Ticket')) }} {{ macro.badge_danger(status|sov_trans_admin_choice('status','Ticket')) }}
{% endif %} {% endif %}

+ 1
- 1
Resources/views/admin/ticket/macro.html.twig View File

<th>Sujet</th> <th>Sujet</th>
<th>Statut</th> <th>Statut</th>
<th>Dernier message</th> <th>Dernier message</th>
<th></th>
<th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

+ 4
- 2
Resources/views/adminlte/block/menu.html.twig View File

{% if item.icon is not empty %} {% if item.icon is not empty %}
<i class="{{ item.icon }} nav-icon"></i> <i class="{{ item.icon }} nav-icon"></i>
{% endif %} {% endif %}
<p>{{ item.label|sov_trans_admin_menu }}</p>

<p>{{ item.label|sov_trans_admin_menu(item.translationParameters)|raw }}</p>

{% if item.hasSubItems %}<i class="right fas fa-angle-left"></i>{% endif %} {% if item.hasSubItems %}<i class="right fas fa-angle-left"></i>{% endif %}
</a> </a>
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>


{% block main_menu_after %}{% endblock %}
{% block main_menu_after %}{% endblock %}

+ 8
- 8
Resources/views/adminlte/block/navbar_header.html.twig View File

Pense-bête Pense-bête
</a> </a>
</li> </li>
{# TODO Adapter Pour Caracole #}
{# <li class="nav-item">#}
{# <a href="{{ path(sov_homepage_route(), {section: section_slug_current()}) }}" class="btn btn-sm btn-block btn-outline-success" target="_blank"#}
{# rel="noreferrer">#}
{# <i class="action-icon fa fa-eye"></i>#}
{# Afficher le site#}
{# </a>#}
{# </li>#}
<li class="nav-item">
<a href="{{ path(sov_homepage_route()) }}" class="btn btn-sm btn-block btn-outline-success" target="_blank"
rel="noreferrer">
<i class="action-icon fa fa-eye"></i>
Afficher le site
</a>
</li>
</ul> </ul>
</nav> </nav>

+ 12
- 0
Resources/views/adminlte/crud/field/association.html.twig View File

{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #}
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #}
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #}
{% if 'toMany' == field.customOptions.get('associationType') %}
<span class="badge badge-secondary">{{ field.formattedValue }}</span>
{% else %}
{% if field.customOption('crudControllerFqcn') is not null and field.value is not null%}
<a href="{{ ea_url_short(field.customOption('crudControllerFqcn'), 'edit', field.value.id) }}">{{ field.formattedValue }}</a>
{% else %}
{{ field.formattedValue }}
{% endif %}
{% endif %}

+ 3
- 6
Resources/views/adminlte/crud/field/toggle.html.twig View File

{% set id_toggle = 'toggle-'~item.id~'-'~property_name %} {% set id_toggle = 'toggle-'~item.id~'-'~property_name %}


{% block toggle %} {% block toggle %}
<div class="custom-control custom-switch custom-switch-on-success custom-switch-off-default"
<div class="custom-control custom-switch custom-switch-on-success custom-switch-off-default" data-toggle="tooltip" title="{{ field.getCustomOption('toggle_label') ? field.label : field.property|sov_trans_admin_field(entity.instance) }}"
data-url="{{ ea_url({crudAction: 'edit', entityId: item.id, fieldName: property_name }) }}"> data-url="{{ ea_url({crudAction: 'edit', entityId: item.id, fieldName: property_name }) }}">
<input type="checkbox" class="custom-control-input" id="{{ id_toggle }}" {{ field.value ? 'checked' }}>
<label class="custom-control-label" for="{{ id_toggle }}">
{% block label %}
{{ field.getCustomOption('toggle_label') ? field.label : field.property|sov_trans_admin_field(entity.instance) }}
{% endblock label %}
<input type="checkbox" class="custom-control-input" id="{{ id_toggle }}" {{ field.value ? 'checked' }}>
<label class="custom-control-label" for="{{ id_toggle }}" >
</label> </label>
</div> </div>
{% endblock toggle %} {% endblock toggle %}

+ 6
- 0
Resources/views/adminlte/crud/form_theme.html.twig View File

{% block class %}{{ loop.first ? 'active' }}{% endblock %} {% block class %}{{ loop.first ? 'active' }}{% endblock %}
{% block id %}{{ panel_name }}{% endblock %} {% block id %}{{ panel_name }}{% endblock %}
{% block content %} {% block content %}
{% if panel_config['prepend_content_path'] is defined %}
{% include panel_config['prepend_content_path'] %}
{% endif %}
{% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and field.vars.ea_crud_form.form_panel == panel_name) %} {% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and field.vars.ea_crud_form.form_panel == panel_name) %}
{% if not field.vars.ea_crud_form.form_tab or field.vars.ea_crud_form.form_tab == tab_name %} {% if not field.vars.ea_crud_form.form_tab or field.vars.ea_crud_form.form_tab == tab_name %}
{{ form_row(field) }} {{ form_row(field) }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if panel_config['append_content_path'] is defined %}
{% include panel_config['append_content_path'] %}
{% endif %}
{% endblock %} {% endblock %}
{% endembed %} {% endembed %}
{% else %} {% else %}

+ 7
- 5
Resources/views/adminlte/crud/index.html.twig View File





<div class="btn-list float-sm-right"> <div class="btn-list float-sm-right">
{% block global_actions %}
<div class="global-actions">
<div class="global-actions">

{% block global_actions %}
{% for action in global_actions %} {% for action in global_actions %}
{{ include(action.templatePath, { action: action }, with_context = false) }} {{ include(action.templatePath, { action: action }, with_context = false) }}
{% endfor %} {% endfor %}
</div>
{% endblock global_actions %}
{% endblock global_actions %}
</div>

{% block batch_actions %} {% block batch_actions %}
{% if has_batch_actions %} {% if has_batch_actions %}
<div class="batch-actions" style="display: none"> <div class="batch-actions" style="display: none">
{% endblock %} {% endblock %}
{% block card_body_wrapper %} {% block card_body_wrapper %}
<div class="card-body"> <div class="card-body">
<div class="table-responsive">
<div class="">
<table class="table table-bordered table-hover table-striped"> <table class="table table-bordered table-hover table-striped">
<thead> <thead>
{% block table_head %} {% block table_head %}

+ 7
- 1
Resources/views/adminlte/crud/sort.html.twig View File

{% set is_sorting_field = ea.search.isSortingField(field.property) %} {% set is_sorting_field = ea.search.isSortingField(field.property) %}
<th class="{{ is_sorting_field ? 'sorted' }} {{ field.isVirtual ? 'field-virtual' }} {% if field.textAlign %}text-{{ field.textAlign }}{% endif %}" <th class="{{ is_sorting_field ? 'sorted' }} {{ field.isVirtual ? 'field-virtual' }} {% if field.textAlign %}text-{{ field.textAlign }}{% endif %}"
dir="{{ ea.i18n.textDirection }}"> dir="{{ ea.i18n.textDirection }}">
<span>{{ field.label ? field.label|raw : field.getProperty|raw }}</span>
<span>
{% if field.label is not null %}
{{ field.label|raw }}
{% else %}
{{ field.getProperty|sov_trans_admin_field_index(translation_entity_name) }}
{% endif %}
</span>
</th> </th>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

+ 0
- 2
Resources/views/adminlte/layout.html.twig View File

{% endif %} {% endif %}
{% endif %} {% endif %}




{% block append_body %}{% endblock %} {% block append_body %}{% endblock %}


</body> </body>

+ 5
- 1
Resources/views/adminlte/macro/badge.html.twig View File

{{ _self.badge('danger', title) }} {{ _self.badge('danger', title) }}
{% endmacro %} {% endmacro %}


{% macro badge_info(title) %}
{{ _self.badge('info', title) }}
{% endmacro %}

{% macro badge(status, title) %} {% macro badge(status, title) %}
<span class="badge badge-{{ status }}">{{ title }}</span> <span class="badge badge-{{ status }}">{{ title }}</span>
{% endmacro %}
{% endmacro %}

+ 3
- 2
Solver/Ticket/TicketSolver.php View File



class TicketSolver class TicketSolver
{ {
public function getTypeChoices(): array
public static function getTypeChoices(): array
{ {
return [ return [
TicketModel::TYPE_GENERAL_QUESTION, TicketModel::TYPE_GENERAL_QUESTION,
]; ];
} }


public function getStatusChoices(): array
public static function getStatusChoices(): array
{ {
return [ return [
TicketModel::TICKET_STATUS_OPEN, TicketModel::TICKET_STATUS_OPEN,
TicketModel::TICKET_STATUS_BEING_PROCESSED, TicketModel::TICKET_STATUS_BEING_PROCESSED,
TicketModel::TICKET_STATUS_PROCESSED,
TicketModel::TICKET_STATUS_CLOSED, TicketModel::TICKET_STATUS_CLOSED,
]; ];
} }

+ 2
- 2
Translation/TranslatorAdmin.php View File

return $this->trans('action.' . $action); return $this->trans('action.' . $action);
} }


public function transMenu($menu): string
public function transMenu($menu, $params = []): string
{ {
return $this->trans('menu.' . $menu);
return $this->trans('menu.' . $menu, $params);
} }


public function transFlashMessage($type, $name, $entityClass = false, $params = []): string public function transFlashMessage($type, $name, $entityClass = false, $params = []): string

+ 1
- 1
Twig/StoreTwigExtension.php View File



public function getReminders($params) public function getReminders($params)
{ {
//TODO !!!!!!
// @TODO : à faire
return array(); return array();
} }



+ 2
- 2
Twig/TranslatorTwigExtension.php View File

return $this->translatorAdmin->transCard($cardName, $entityClass); return $this->translatorAdmin->transCard($cardName, $entityClass);
} }


public function transAdminMenu($menuName)
public function transAdminMenu($menuName, $params = [])
{ {
return $this->translatorAdmin->transMenu($menuName);;
return $this->translatorAdmin->transMenu($menuName, $params);;
} }


public function transAdminAction($actionName) public function transAdminAction($actionName)

+ 16
- 0
Twig/TwigExtension.php View File

use Lc\SovBundle\Component\FileComponent; use Lc\SovBundle\Component\FileComponent;
use Lc\SovBundle\Component\MetaComponent; use Lc\SovBundle\Component\MetaComponent;
use Lc\SovBundle\Component\StringComponent; use Lc\SovBundle\Component\StringComponent;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Form\Newsletter\NewsletterType; use Lc\SovBundle\Form\Newsletter\NewsletterType;
use Lc\SovBundle\Model\File\FileInterface; use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Repository\Reminder\ReminderStore; use Lc\SovBundle\Repository\Reminder\ReminderStore;
new TwigFunction('day_by_number', [$this, 'getDayByNumber']), new TwigFunction('day_by_number', [$this, 'getDayByNumber']),
new TwigFunction('user_current', [$this, 'getUserCurrent']), new TwigFunction('user_current', [$this, 'getUserCurrent']),
new TwigFunction('ea_url_short', [$this, 'generateEaUrl']), new TwigFunction('ea_url_short', [$this, 'generateEaUrl']),
new TwigFunction('is_instance_of', [$this, 'isInstanceOf']),
]; ];
} }


]; ];
} }


public function isInstanceOf(EntityInterface $entity, string $interfaceName)
{
$reflection = new \ReflectionClass($entity);
$interfaceNameArray = $reflection->getInterfaceNames();

foreach($interfaceNameArray as $interfaceNameEntity) {
if(strpos($interfaceNameEntity, $interfaceName) !== false) {
return true;
}
}

return false;
}

public function sovCache($file) public function sovCache($file)
{ {
$cacheTime = filemtime($this->kernel->getProjectDir() . '/public' . $file); $cacheTime = filemtime($this->kernel->getProjectDir() . '/public' . $file);

Loading…
Cancel
Save