@@ -3,6 +3,7 @@ | |||
namespace Lc\SovBundle\Builder\Ticket; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Event\Ticket\TicketEvent; | |||
use Lc\SovBundle\Notification\MailMailjetNotification; | |||
use Lc\SovBundle\Component\FormComponent; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactory; | |||
@@ -10,6 +11,8 @@ use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
use Lc\SovBundle\Repository\User\UserStore; | |||
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\Security; | |||
@@ -23,6 +26,8 @@ class TicketBuilder | |||
protected TicketFactory $ticketFactory; | |||
protected AuthorizationCheckerInterface $authorizationChecker; | |||
protected UserStore $userStore; | |||
protected EventDispatcherInterface $eventDispatcher; | |||
public function __construct( | |||
Security $security, | |||
@@ -32,7 +37,8 @@ class TicketBuilder | |||
ParameterBagInterface $parameterBag, | |||
AuthorizationCheckerInterface $authorizationChecker, | |||
TicketFactory $ticketFactory, | |||
UserStore $userStore | |||
UserStore $userStore, | |||
EventDispatcherInterface $eventDispatcher | |||
) { | |||
$this->security = $security; | |||
$this->entityManager = $entityManager; | |||
@@ -42,6 +48,7 @@ class TicketBuilder | |||
$this->ticketFactory = $ticketFactory; | |||
$this->userStore = $userStore; | |||
$this->authorizationChecker = $authorizationChecker; | |||
$this->eventDispatcher = $eventDispatcher; | |||
} | |||
public function create(array $params = []): TicketInterface | |||
@@ -50,64 +57,11 @@ class TicketBuilder | |||
$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->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; | |||
} | |||
@@ -115,13 +69,17 @@ class TicketBuilder | |||
public function init(TicketInterface $ticket, array $params = []): void | |||
{ | |||
$user = $this->security->getUser(); | |||
if($user) { | |||
if ($user) { | |||
$ticket->setCreatedBy($user); | |||
} | |||
if (isset($params['section'])) { | |||
$ticket->setSection($params['section']); | |||
} | |||
$ticket->setMerchant($params['merchant']); | |||
if (isset($params['user'])) { | |||
$ticket->setUser($params['user']); | |||
} else { | |||
$ticket->setVisitorFirstname($params['visitorFirstname']); | |||
$ticket->setVisitorLastname($params['visitorLastname']); |
@@ -3,6 +3,7 @@ | |||
namespace Lc\SovBundle\Builder\Ticket; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Event\Ticket\TicketEvent; | |||
use Lc\SovBundle\Notification\MailMailjetNotification; | |||
use Lc\SovBundle\Component\FormComponent; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactory; | |||
@@ -11,21 +12,25 @@ use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |||
class TicketMessageBuilder | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
protected MailMailjetNotification $mailMailjetNotification; | |||
protected TicketMessageFactory $ticketMessageFactory; | |||
protected EventDispatcherInterface $eventDispatcher; | |||
public function __construct( | |||
EntityManagerInterface $entityManager, | |||
MailMailjetNotification $mailMailjetNotification, | |||
TicketMessageFactory $ticketMessageFactory | |||
TicketMessageFactory $ticketMessageFactory, | |||
EventDispatcherInterface $eventDispatcher | |||
) { | |||
$this->entityManager = $entityManager; | |||
$this->mailMailjetNotification = $mailMailjetNotification; | |||
$this->ticketMessageFactory = $ticketMessageFactory; | |||
$this->eventDispatcher = $eventDispatcher; | |||
} | |||
public function create(array $params = []): TicketMessageInterface | |||
@@ -36,24 +41,8 @@ class TicketMessageBuilder | |||
$ticketMessage->setStatus(1); | |||
$ticketMessage->setTicket($ticket); | |||
$ticketMessage->setMessage($params['message']); | |||
if (isset($params['answerByAdmin']) && $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); | |||
@@ -66,9 +55,12 @@ class TicketMessageBuilder | |||
$ticket->setUpdatedAt(new \DateTime()); | |||
$this->entityManager->persist($ticket); | |||
$this->entityManager->create($ticket); | |||
$this->entityManager->flush(); | |||
$this->eventDispatcher->dispatch(new TicketEvent($ticket), TicketEvent::NEW_MESSAGE_EVENT); | |||
return $ticketMessage; | |||
} | |||
@@ -3,6 +3,7 @@ | |||
namespace Lc\SovBundle\Container\Ticket; | |||
use Lc\SovBundle\Builder\Ticket\TicketBuilder; | |||
use Lc\SovBundle\Definition\Field\Ticket\TicketFieldDefinition; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactory; | |||
use Lc\SovBundle\Repository\Ticket\TicketRepositoryQuery; | |||
use Lc\SovBundle\Repository\Ticket\TicketStore; | |||
@@ -15,19 +16,22 @@ class TicketContainer | |||
protected TicketRepositoryQuery $repositoryQuery; | |||
protected TicketStore $store; | |||
protected TicketSolver $solver; | |||
protected TicketFieldDefinition $fieldDefinition; | |||
public function __construct( | |||
TicketFactory $factory, | |||
TicketBuilder $builder, | |||
TicketRepositoryQuery $repositoryQuery, | |||
TicketStore $store, | |||
TicketSolver $solver | |||
TicketSolver $solver, | |||
TicketFieldDefinition $fieldDefinition | |||
) { | |||
$this->factory = $factory; | |||
$this->builder = $builder; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
$this->solver = $solver; | |||
$this->fieldDefinition = $fieldDefinition; | |||
} | |||
public function getFactory(): TicketFactory | |||
@@ -54,4 +58,9 @@ class TicketContainer | |||
{ | |||
return $this->solver; | |||
} | |||
public function getFieldDefinition(): TicketFieldDefinition | |||
{ | |||
return $this->fieldDefinition; | |||
} | |||
} |
@@ -41,12 +41,14 @@ use Lc\SovBundle\Definition\ActionDefinition; | |||
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SeoInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SortableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\StatusInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TreeInterface; | |||
use Lc\SovBundle\Field\CollectionField; | |||
use Lc\SovBundle\Field\Filter\FilterManager; | |||
use Lc\SovBundle\Form\Common\FiltersFormType; | |||
use Lc\SovBundle\Form\Common\PositionType; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
use Lc\SovBundle\Repository\EntityRepository; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\FlashBagTranslator; | |||
@@ -62,6 +64,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
use ControllerTrait; | |||
protected FormInterface $filtersForm; | |||
protected bool $isRepositoryQueryFiltered = false; | |||
abstract public function getRepositoryQuery(): RepositoryQueryInterface; | |||
@@ -77,16 +80,9 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { | |||
$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()); | |||
@@ -116,9 +112,9 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
if ($entity !== null) { | |||
if ($entity->getParent() !== null) { | |||
$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); | |||
} | |||
} else { | |||
@@ -130,22 +126,42 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$entityId = $context->getRequest()->get('entityId'); | |||
if ($entityId != null) { | |||
$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); | |||
} | |||
} | |||
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 | |||
{ | |||
$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()]); | |||
@@ -169,7 +185,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults); | |||
} | |||
$maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get( | |||
$paramSessionListMaxResults | |||
$paramSessionListMaxResults | |||
) : 30; | |||
$crud->setPaginatorPageSize($maxResults); | |||
@@ -179,17 +195,17 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
if ($this->isInstanceOf(SeoInterface::class)) { | |||
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(), | |||
CollectionField::new('oldUrls') | |||
->setFormTypeOption('entry_type', TextType::class)->setLabel( | |||
'Anciennes urls du document' | |||
)->hideOnIndex(), | |||
]; | |||
} else { | |||
return null; | |||
@@ -200,8 +216,8 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
if ($this->isInstanceOf(DevAliasInterface::class)) { | |||
return [ | |||
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'), | |||
TextField::new('devAlias')->hideOnIndex(), | |||
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'), | |||
TextField::new('devAlias')->hideOnIndex(), | |||
]; | |||
} else { | |||
return null; | |||
@@ -223,27 +239,28 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); | |||
$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); | |||
$entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults()); | |||
$this->get(EntityFactory::class)->processFieldsForAll($entities, $fields); | |||
$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()); | |||
$repository = $entityManager->getRepository($this->getEntityFqcn()); | |||
@@ -270,26 +287,26 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
} | |||
$url = $this->get(AdminUrlGenerator::class) | |||
->setAction(ActionDefinition::INDEX) | |||
->generateUrl(); | |||
->setAction(ActionDefinition::INDEX) | |||
->generateUrl(); | |||
$this->addFlashTranslator('success', 'sorted'); | |||
return $this->redirect($url); | |||
} | |||
$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')); | |||
$event = new AfterCrudActionEvent($context, $responseParameters); | |||
@@ -302,14 +319,14 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
} | |||
public function duplicate( | |||
AdminContext $context, | |||
EntityComponent $entityComponent, | |||
TranslatorAdmin $translatorAdmin, | |||
EntityManagerInterface $em | |||
AdminContext $context, | |||
EntityComponent $entityComponent, | |||
TranslatorAdmin $translatorAdmin, | |||
EntityManagerInterface $em | |||
) { | |||
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); | |||
} | |||
@@ -323,23 +340,35 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$em->flush(); | |||
$url = $this->get(AdminUrlGenerator::class) | |||
->setAction(ActionDefinition::EDIT) | |||
->setEntityId($newEntity->getId()) | |||
->generateUrl(); | |||
->setAction(ActionDefinition::EDIT) | |||
->setEntityId($newEntity->getId()) | |||
->generateUrl(); | |||
$this->addFlashTranslator('success', 'duplicated'); | |||
return $this->redirect($url); | |||
} | |||
public function isRepositoryQueryFiltered():bool{ | |||
if(($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered){ | |||
return true; | |||
}else{ | |||
return false; | |||
} | |||
} | |||
public function createIndexRepositoryQuery( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
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 | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
@@ -349,6 +378,9 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$repositoryQuery->filterIsParent(); | |||
} | |||
} | |||
if ($this->isInstanceOf(StatusInterface::class)) { | |||
$repositoryQuery->filterIsOnlineAndOffline(); | |||
} | |||
$this->filtersForm = $this->createForm( | |||
FiltersFormType::class, | |||
@@ -365,30 +397,37 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$this->filtersForm->handleRequest($searchDto->getRequest()); | |||
$filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto); | |||
$this->isRepositoryQueryFiltered = $filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto); | |||
return $repositoryQuery; | |||
} | |||
public function createIndexQueryBuilder( | |||
public function createSortRepositoryQuery( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
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( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): 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) | |||
@@ -408,7 +447,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$context = $this->get(AdminContextProvider::class)->getContext(); | |||
return $context->getCrudControllers()->findCrudFqcnByEntityFqcn( | |||
$this->get(EntityManagerInterface::class)->getEntityName($interface) | |||
$this->get(EntityManagerInterface::class)->getEntityName($interface) | |||
); | |||
} | |||
@@ -431,7 +470,6 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$entityManager->delete($entityInstance); | |||
$entityManager->flush(); | |||
$this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName()); | |||
} | |||
public function configureActions(Actions $actions): Actions | |||
@@ -453,13 +491,13 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
public function getDuplicateAction(): Action | |||
{ | |||
$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; | |||
} | |||
@@ -469,67 +507,67 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction()); | |||
$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( | |||
$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( | |||
$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( | |||
$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( | |||
$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'), | |||
] | |||
); | |||
} | |||
@@ -541,47 +579,47 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$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( | |||
$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( | |||
$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( | |||
$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'), | |||
] | |||
); | |||
} | |||
@@ -594,35 +632,35 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$actions->add(Crud::PAGE_NEW, ActionDefinition::INDEX); | |||
$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( | |||
$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( | |||
$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'), | |||
] | |||
); | |||
} | |||
@@ -630,13 +668,13 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
if ($this->isInstanceOf(TranslatableInterface::class)) { | |||
$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; | |||
} | |||
); | |||
} | |||
} | |||
@@ -644,38 +682,41 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
public function handleSortableEntityActions(Actions $actions): void | |||
{ | |||
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); | |||
} | |||
} | |||
public function handleTreeEntityActions(Actions $actions): void | |||
{ | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$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( | |||
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, $indexChildAction); | |||
@@ -686,35 +727,35 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) { | |||
$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; | |||
} | |||
); | |||
} | |||
} | |||
@@ -722,22 +763,22 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
public function autocompleteFilter(AdminContext $context): JsonResponse | |||
{ | |||
$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); | |||
/** @var CrudControllerInterface $controller */ | |||
$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 */ | |||
$field = FieldCollection::new( | |||
$controller->configureFields($autocompleteContext['originatingPage']) | |||
$controller->configureFields($autocompleteContext['originatingPage']) | |||
)->getByProperty($autocompleteContext['propertyName']); | |||
$filterManager = $this->get(FilterManager::class); | |||
@@ -762,15 +803,15 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
if ($dataInOption) { | |||
$data = $entity; | |||
}else{ | |||
} else { | |||
$data = null; | |||
} | |||
$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); | |||
} |
@@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\CaracoleBundle\Resolver\MerchantResolver; | |||
use Lc\CaracoleBundle\Resolver\SectionResolver; | |||
use Lc\SovBundle\Container\Reminder\ReminderContainer; | |||
use Lc\SovBundle\Controller\ControllerTrait; | |||
use Lc\SovBundle\Factory\Reminder\ReminderFactory; | |||
use Lc\SovBundle\Form\Reminder\ReminderAdminFormType; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
@@ -19,6 +20,7 @@ use Symfony\Component\Routing\Annotation\Route; | |||
class ReminderAdminController extends AbstractController | |||
{ | |||
use ControllerTrait; | |||
protected EntityManagerInterface $entityManager; | |||
protected ReminderContainer $reminderContainer; |
@@ -3,134 +3,105 @@ | |||
namespace Lc\SovBundle\Controller\Ticket; | |||
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\Assets; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
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 Lc\SovBundle\Container\Ticket\TicketContainer; | |||
use Lc\SovBundle\Container\Ticket\TicketMessageContainer; | |||
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\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
abstract class TicketAdminController extends AbstractAdminController | |||
{ | |||
public function getRepositoryQuery() :RepositoryQueryInterface | |||
public function getRepositoryQuery(): RepositoryQueryInterface | |||
{ | |||
return $this->getTicketContainer()->getRepositoryQuery(); | |||
} | |||
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 | |||
{ | |||
$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) | |||
{ | |||
@@ -138,20 +109,20 @@ abstract class TicketAdminController extends AbstractAdminController | |||
$ticket = $context->getEntity()->getInstance(); | |||
$url = $adminUrlGenerator | |||
->setAction('ticketStatusAction') | |||
->generateUrl(); | |||
->setAction('ticketStatusAction') | |||
->generateUrl(); | |||
$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); | |||
$formAddTicketMessage = $this->createForm(TicketMessageFormType::class, $ticketMessage); | |||
$formAddTicketMessage = $this->createForm(TicketMessageAdminFormType::class, $ticketMessage); | |||
$formAddTicketMessage->handleRequest($this->get(RequestStack::class)->getMainRequest()); | |||
if ($formAddTicketMessage->isSubmitted() && $formAddTicketMessage->isValid()) { | |||
@@ -160,31 +131,36 @@ abstract class TicketAdminController extends AbstractAdminController | |||
$ticketMessage->setAnswerByAdmin(true); | |||
$this->get(EntityManagerInterface::class)->create($ticketMessage); | |||
$this->get(EntityManagerInterface::class)->flush(); | |||
$this->getEventDispatcher()->dispatch(new TicketEvent($ticket), TicketEvent::NEW_MESSAGE_EVENT); | |||
return $this->redirect($this->generateEaUrl()); | |||
} | |||
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->handleRequest($request); | |||
$formTicketStatusForm->handleRequest($context->getRequest()); | |||
$success = false; | |||
if ($formTicketStatusForm->isSubmitted() && $formTicketStatusForm->isValid()) { | |||
$this->get('em')->persist($ticket); | |||
$this->get('em')->flush(); | |||
$entityManager->update($ticket); | |||
$entityManager->flush(); | |||
$success = true; | |||
} | |||
@@ -2,11 +2,16 @@ | |||
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\EmailField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\User\UserContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Definition\ActionDefinition; | |||
use Lc\SovBundle\Definition\RolesDefinition; | |||
use Lc\SovBundle\Definition\RolesDefinitionInterface; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
@@ -19,14 +24,40 @@ abstract class UserAdminController extends AbstractAdminController | |||
{ | |||
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 |
@@ -15,4 +15,7 @@ class ActionDefinition { | |||
public const SAVE_AND_ADD_ANOTHER = 'saveAndAddAnother'; | |||
public const SAVE_AND_CONTINUE = 'saveAndContinue'; | |||
public const SAVE_AND_RETURN = 'saveAndReturn'; | |||
public const SWITCH_USER = 'switchUser'; | |||
public const WRITE_TO_USER = 'writeToUser'; | |||
} |
@@ -3,6 +3,7 @@ | |||
namespace Lc\SovBundle\Definition\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField; | |||
@@ -46,6 +47,8 @@ abstract class AbstractFieldDefinition | |||
->hideOnIndex(), | |||
'devAlias' => TextField::new('devAlias')->hideOnIndex(), | |||
'status' => StatusField::new('status')->setSortable(true), | |||
'createdAt' => DateTimeField::new('createdAt')->setSortable(true), | |||
'updatedAt' => DateTimeField::new('updatedAt')->setSortable(true), | |||
]; | |||
} | |||
@@ -174,10 +177,22 @@ abstract class AbstractFieldDefinition | |||
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( | |||
['panel_' . $panel => FormField::addPanel($panel)], | |||
[ | |||
'panel_' . $panel => $fieldPanel | |||
], | |||
$this->buildFieldArray($panelFieldArray) | |||
); | |||
} | |||
} | |||
} |
@@ -5,10 +5,10 @@ namespace Lc\SovBundle\Definition\Field\Site; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition; | |||
use Lc\SovBundle\Field\BooleanField; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\ImageManagerField; | |||
class NewsFieldDefinition extends AbstractFieldDefinition | |||
@@ -50,7 +50,7 @@ class NewsFieldDefinition extends AbstractFieldDefinition | |||
'newsletter' => AssociationField::new('newsletter')->setSortable(true), | |||
'image' => ImageManagerField::new('image'), | |||
'position' => NumberField::new('position'), | |||
'description' => TextEditorField::new('description'), | |||
'description' => CKEditorField::new('description'), | |||
'isSent' => BooleanField::new('isSent')->setSortable(true), | |||
]; | |||
} |
@@ -0,0 +1,118 @@ | |||
<?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) | |||
]; | |||
} | |||
} |
@@ -11,6 +11,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\CaracoleBundle\Field\AssociationField; | |||
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition; | |||
use Lc\SovBundle\Definition\RolesDefinition; | |||
use Lc\SovBundle\Solver\Ticket\TicketSolver; | |||
use Lc\SovBundle\Solver\User\UserSolver; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
@@ -47,7 +48,8 @@ class UserFieldDefinition extends AbstractFieldDefinition | |||
'email', | |||
'phone', | |||
'birthdate', | |||
'groupUsers' | |||
'groupUsers', | |||
'ticketTypesNotification' | |||
]; | |||
} | |||
@@ -70,8 +72,19 @@ class UserFieldDefinition extends AbstractFieldDefinition | |||
'firstname' => TextField::new('firstname')->setSortable(true), | |||
'email' => TextField::new('email')->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), | |||
'ticketTypesNotification' => ChoiceField::new('ticketTypesNotification') | |||
->setSortable(true) | |||
->setFormTypeOption('expanded', false) | |||
->setFormTypeOption('multiple', true) | |||
->setChoices($this->translatorAdmin->transChoices( | |||
TicketSolver::getTypeChoices(), | |||
'Ticket', | |||
'type' | |||
)), | |||
'roles' => ChoiceField::new('roles') | |||
->allowMultipleChoices() | |||
->autocomplete() |
@@ -35,29 +35,12 @@ class SiteSettingDefinition extends AbstractSettingDefinition implements SiteSet | |||
'name' => self::SETTING_MAINTENANCE_IP_AUTHORIZED, | |||
] | |||
); | |||
$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() | |||
{ | |||
return [ | |||
self::CATEGORY_GENERAL, | |||
self::CATEGORY_EMAIL | |||
]; | |||
} | |||
@@ -0,0 +1,30 @@ | |||
<?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; | |||
} | |||
} |
@@ -105,5 +105,4 @@ class SiteSettingEventSubscriber implements EventSubscriberInterface | |||
{ | |||
return $this->siteStore->getOneByDevAlias('default'); | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
<?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], | |||
], | |||
] | |||
); | |||
} | |||
} | |||
} | |||
} |
@@ -12,6 +12,8 @@ class NewsFactory extends AbstractFactory implements NewsFactoryInterface | |||
{ | |||
$news = new News(); | |||
$news->setStatus(1); | |||
return $news; | |||
} | |||
@@ -12,6 +12,8 @@ class PageFactory extends AbstractFactory implements PageFactoryInterface | |||
{ | |||
$page = new Page(); | |||
$page->setStatus(1); | |||
return $page; | |||
} | |||
} |
@@ -12,6 +12,8 @@ class GroupUserFactory extends AbstractFactory implements GroupUserFactoryInterf | |||
{ | |||
$groupUser = new GroupUser(); | |||
$groupUser->setStatus(1); | |||
return $groupUser; | |||
} | |||
} |
@@ -19,7 +19,7 @@ final class BooleanField implements FieldInterface | |||
return (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setTemplatePath('@LcSov/adminlte/crud/field/boolean.html.twig') | |||
->setTemplatePath('@LcSov/adminlte/crud/field/toggle.html.twig') | |||
->setFormType(CheckboxType::class); | |||
} | |||
@@ -53,23 +53,10 @@ class ChoiceFilter | |||
{ | |||
$fieldProperty = $this->getFieldProperty($fieldDto); | |||
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( | |||
'.'.$fieldProperty.' LIKE :'.$fieldProperty.'' | |||
); | |||
$repositoryQuery->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
$repositoryQuery->setParameter($fieldProperty, $filteredValue); | |||
} | |||
} |
@@ -29,6 +29,7 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
class FilterManager | |||
{ | |||
protected $em; | |||
protected bool $isFiltered = false; | |||
use FilterTrait; | |||
@@ -39,7 +40,7 @@ class FilterManager | |||
} | |||
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) { | |||
@@ -65,17 +66,25 @@ class FilterManager | |||
$fieldDto->getProperty(), | |||
'dateEnd' | |||
); | |||
if($filteredValue['dateStart'] || $filteredValue['dateEnd']){ | |||
$this->isFiltered = true; | |||
} | |||
} else { | |||
$filteredValue['value'] = $this->getFilteredValue( | |||
$filtersForm, | |||
$entityDto->getFqcn(), | |||
$fieldDto->getProperty() | |||
); | |||
if($filteredValue['value'] ){ | |||
$this->isFiltered = true; | |||
} | |||
} | |||
$this->applyFilter($repositoryQuery, $fieldDto, $filteredValue); | |||
} | |||
} | |||
} | |||
return $this->isFiltered; | |||
} | |||
@@ -88,7 +97,7 @@ class FilterManager | |||
$customFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']); | |||
} else { | |||
switch ($this->guessFormType($fieldDto)) { | |||
switch ($fieldDto->getFormType()) { | |||
case CheckboxType::class: | |||
$checkboxFilter = new CheckboxFilter(); | |||
@@ -183,14 +192,4 @@ class FilterManager | |||
} | |||
} | |||
protected function guessFormType(FieldDto $fieldDto) | |||
{ | |||
if ($fieldDto->getCustomOption('filter_type')) { | |||
return $fieldDto->getCustomOption('filter_type'); | |||
} else { | |||
return $fieldDto->getFormType(); | |||
} | |||
} | |||
} |
@@ -41,9 +41,9 @@ trait FilterTrait | |||
{ | |||
$property = $fieldDto->getProperty(); | |||
//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; | |||
} | |||
@@ -0,0 +1,38 @@ | |||
<?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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?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); | |||
} | |||
} | |||
} |
@@ -21,16 +21,13 @@ class TicketFormType extends AbstractType | |||
{ | |||
protected EntityManager $entityManager; | |||
protected TranslatorAdmin $translatorAdmin; | |||
protected TicketSolver $ticketSolver; | |||
public function __construct( | |||
EntityManager $entityManager, | |||
TranslatorAdmin $translatorAdmin, | |||
TicketSolver $ticketSolver | |||
TranslatorAdmin $translatorAdmin | |||
) { | |||
$this->entityManager = $entityManager; | |||
$this->translatorAdmin = $translatorAdmin; | |||
$this->ticketSolver = $ticketSolver; | |||
} | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
@@ -45,24 +42,24 @@ class TicketFormType extends AbstractType | |||
] | |||
); | |||
$builder->add( | |||
'subject', | |||
TextType::class | |||
); | |||
$builder->add( | |||
'type', | |||
ChoiceType::class, | |||
[ | |||
'label' => 'Type', | |||
'choices' => $this->translatorAdmin->transChoices( | |||
$this->ticketSolver->getTypeChoices(), | |||
TicketSolver::getTypeChoices(), | |||
'Ticket', | |||
'type' | |||
), | |||
] | |||
); | |||
$builder->add( | |||
'subject', | |||
TextType::class | |||
); | |||
$builder->add( | |||
'ticketMessages', | |||
CollectionType::class, | |||
@@ -93,4 +90,4 @@ class TicketFormType extends AbstractType | |||
] | |||
); | |||
} | |||
} | |||
} |
@@ -6,12 +6,13 @@ use Lc\SovBundle\Doctrine\EntityManager; | |||
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
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\TextareaType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
class TicketMessageFormType extends AbstractType | |||
class TicketMessageAdminFormType extends AbstractType | |||
{ | |||
protected $em; | |||
protected $translatorAdmin; | |||
@@ -31,13 +32,12 @@ class TicketMessageFormType extends AbstractType | |||
'required' => true | |||
] | |||
); | |||
$builder->add( | |||
'submit', | |||
SubmitType::class, | |||
[ | |||
'label' => $this->translatorAdmin->transAction('send') | |||
] | |||
'answerByAdmin', | |||
HiddenType::class, | |||
[ | |||
'data' => 1 | |||
] | |||
); | |||
} | |||
@@ -2,26 +2,24 @@ | |||
namespace Lc\SovBundle\Form\Ticket; | |||
use App\Entity\Address; | |||
use App\Entity\OrderShop; | |||
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\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\TextareaType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
use Symfony\Component\Security\Core\Security; | |||
use Symfony\Component\Validator\Constraints\File; | |||
class TicketMessageType extends AbstractType | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->entityManager = $entityManager; | |||
} | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
{ | |||
@@ -51,13 +49,14 @@ class TicketMessageType extends AbstractType | |||
'label' => 'entity.TicketMessage.fields.closeTicket', | |||
'translation_domain' => 'admin', | |||
'required' => false, | |||
'mapped' => false, | |||
]); | |||
} | |||
public function configureOptions(OptionsResolver $resolver) | |||
{ | |||
$resolver->setDefaults([ | |||
// Configure your form options here | |||
'data_class' => $this->entityManager->getEntityName(TicketMessageInterface::class), | |||
]); | |||
} | |||
} |
@@ -17,7 +17,6 @@ abstract class TicketMessageModel extends AbstractLightEntity implements TicketM | |||
{ | |||
use StatusTrait; | |||
/** | |||
* @ORM\Column(type="text") | |||
*/ | |||
@@ -41,7 +40,7 @@ abstract class TicketMessageModel extends AbstractLightEntity implements TicketM | |||
public function __toString() | |||
{ | |||
return $this->message; | |||
return ''.$this->message; | |||
} | |||
public function getMessage(): ?string |
@@ -22,6 +22,7 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac | |||
const TICKET_STATUS_OPEN = 'open'; | |||
const TICKET_STATUS_BEING_PROCESSED = 'being-processed'; | |||
const TICKET_STATUS_PROCESSED = 'processed'; | |||
const TICKET_STATUS_CLOSED = 'closed'; | |||
/** | |||
@@ -92,7 +93,6 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac | |||
return $this; | |||
} | |||
public function getStatus(): ?string | |||
{ | |||
return $this->status; | |||
@@ -105,7 +105,6 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac | |||
return $this; | |||
} | |||
public function getSubject(): ?string | |||
{ | |||
return $this->subject; |
@@ -134,7 +134,7 @@ abstract class UserModel implements EntityInterface, UserInterface, DevAliasInte | |||
return $this->birthdate; | |||
} | |||
public function setBirthdate(\DateTimeInterface $birthdate): self | |||
public function setBirthdate(?\DateTimeInterface $birthdate): self | |||
{ | |||
$this->birthdate = $birthdate; | |||
@@ -153,9 +153,7 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface | |||
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.'%'); | |||
} | |||
/* |
@@ -8,6 +8,9 @@ use Lc\SovBundle\Repository\AbstractRepositoryQuery; | |||
class TicketRepositoryQuery extends AbstractRepositoryQuery implements TicketRepositoryQueryInterface | |||
{ | |||
protected $isJoinUser = false; | |||
public function __construct(TicketRepository $repository, PaginatorInterface $paginator) | |||
{ | |||
parent::__construct($repository, 'r', $paginator); | |||
@@ -20,6 +23,17 @@ class TicketRepositoryQuery extends AbstractRepositoryQuery implements TicketRep | |||
->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 | |||
{ | |||
return $this | |||
@@ -27,6 +41,33 @@ class TicketRepositoryQuery extends AbstractRepositoryQuery implements TicketRep | |||
->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 | |||
{ | |||
return $this |
@@ -11,4 +11,17 @@ class GroupUserRepositoryQuery extends AbstractRepositoryQuery implements GroupU | |||
{ | |||
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; | |||
} | |||
} |
@@ -27,6 +27,7 @@ class GroupUserStore extends AbstractStore implements GroupUserStoreInterface | |||
public function relationsDefault(RepositoryQueryInterface $query): RepositoryQueryInterface | |||
{ | |||
$query->joinUsers(); | |||
return $query; | |||
} | |||
} |
@@ -14,6 +14,22 @@ class UserRepositoryQuery extends AbstractRepositoryQuery implements UserReposit | |||
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 | |||
{ | |||
return $this |
@@ -26,3 +26,13 @@ table.table { | |||
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%);} |
@@ -20,8 +20,7 @@ function initSovSortableList() { | |||
// Replace '__name__' in the prototype's HTML to | |||
$(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')); | |||
/* if ($('.sov-sortable').data('parent-position') !== '') { | |||
//Ajout d'un 0 initial pour les nuémros <10 |
@@ -8,7 +8,7 @@ menu: | |||
account: Mon compte | |||
account_profile: Informations personnelles | |||
account_password: Mot de passe | |||
tickets: Tickets | |||
tickets: Tickets <span class="float-right badge badge-info">%total_ticket_open%</span> | |||
setting_global: Global | |||
title: | |||
@@ -76,8 +76,8 @@ entity: | |||
label: Ticket | |||
label_plurial: Tickets | |||
fields: | |||
visitorFirstName: Nom | |||
visitorLastName: Prénom | |||
visitorFirstname: Nom | |||
visitorLastname: Prénom | |||
visitorEmail: E-mail | |||
subject: Sujet | |||
type: Type | |||
@@ -91,6 +91,7 @@ entity: | |||
open: Ouvert | |||
being-processed: En attente | |||
closed: Fermé | |||
ticketMessages: Message | |||
TicketModel: | |||
fields: | |||
open: Ouvert | |||
@@ -106,7 +107,7 @@ entity: | |||
default: | |||
fields: | |||
id: Id | |||
createdAt: Créé à | |||
createdAt: Créé le | |||
user: Utilisateur | |||
firstname: Prénom | |||
lastname: Nom |
@@ -86,6 +86,9 @@ | |||
<div class="col-12"> | |||
{{ form_row(form_add_ticket_message.message) }} | |||
</div> | |||
<div class="col-12 text-right"> | |||
<button type="submit" class="btn btn-primary text-right">{{ 'send'|sov_trans_admin_action }}</button> | |||
</div> | |||
</div> | |||
{{ form_end(form_add_ticket_message) }} | |||
</div> |
@@ -1,7 +1,32 @@ | |||
{#{% 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 %} #} | |||
@@ -6,6 +6,8 @@ | |||
{{ macro.badge_success(status|sov_trans_admin_choice('status','Ticket')) }} | |||
{% elseif status == 'being-processed' %} | |||
{{ 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' %} | |||
{{ macro.badge_danger(status|sov_trans_admin_choice('status','Ticket')) }} | |||
{% endif %} |
@@ -5,7 +5,7 @@ | |||
<th>Sujet</th> | |||
<th>Statut</th> | |||
<th>Dernier message</th> | |||
<th></th> | |||
<th>Actions</th> | |||
</tr> | |||
</thead> | |||
<tbody> |
@@ -12,7 +12,9 @@ | |||
{% if item.icon is not empty %} | |||
<i class="{{ item.icon }} nav-icon"></i> | |||
{% 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 %} | |||
</a> | |||
{% endif %} | |||
@@ -46,4 +48,4 @@ | |||
</ul> | |||
</nav> | |||
{% block main_menu_after %}{% endblock %} | |||
{% block main_menu_after %}{% endblock %} |
@@ -44,13 +44,13 @@ | |||
Pense-bête | |||
</a> | |||
</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> | |||
</nav> |
@@ -0,0 +1,12 @@ | |||
{# @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,13 +3,10 @@ | |||
{% set id_toggle = 'toggle-'~item.id~'-'~property_name %} | |||
{% 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 }) }}"> | |||
<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> | |||
</div> | |||
{% endblock toggle %} |
@@ -342,11 +342,17 @@ | |||
{% block class %}{{ loop.first ? 'active' }}{% endblock %} | |||
{% block id %}{{ panel_name }}{% endblock %} | |||
{% 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) %} | |||
{% if not field.vars.ea_crud_form.form_tab or field.vars.ea_crud_form.form_tab == tab_name %} | |||
{{ form_row(field) }} | |||
{% endif %} | |||
{% endfor %} | |||
{% if panel_config['append_content_path'] is defined %} | |||
{% include panel_config['append_content_path'] %} | |||
{% endif %} | |||
{% endblock %} | |||
{% endembed %} | |||
{% else %} |
@@ -45,13 +45,15 @@ | |||
<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 %} | |||
{{ include(action.templatePath, { action: action }, with_context = false) }} | |||
{% endfor %} | |||
</div> | |||
{% endblock global_actions %} | |||
{% endblock global_actions %} | |||
</div> | |||
{% block batch_actions %} | |||
{% if has_batch_actions %} | |||
<div class="batch-actions" style="display: none"> | |||
@@ -66,7 +68,7 @@ | |||
{% endblock %} | |||
{% block card_body_wrapper %} | |||
<div class="card-body"> | |||
<div class="table-responsive"> | |||
<div class=""> | |||
<table class="table table-bordered table-hover table-striped"> | |||
<thead> | |||
{% block table_head %} |
@@ -60,7 +60,13 @@ | |||
{% 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 %}" | |||
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> | |||
{% endif %} | |||
{% endfor %} |
@@ -217,8 +217,6 @@ | |||
{% endif %} | |||
{% endif %} | |||
{% block append_body %}{% endblock %} | |||
</body> |
@@ -10,6 +10,10 @@ | |||
{{ _self.badge('danger', title) }} | |||
{% endmacro %} | |||
{% macro badge_info(title) %} | |||
{{ _self.badge('info', title) }} | |||
{% endmacro %} | |||
{% macro badge(status, title) %} | |||
<span class="badge badge-{{ status }}">{{ title }}</span> | |||
{% endmacro %} | |||
{% endmacro %} |
@@ -7,7 +7,7 @@ use Lc\SovBundle\Model\Ticket\TicketModel; | |||
class TicketSolver | |||
{ | |||
public function getTypeChoices(): array | |||
public static function getTypeChoices(): array | |||
{ | |||
return [ | |||
TicketModel::TYPE_GENERAL_QUESTION, | |||
@@ -15,11 +15,12 @@ class TicketSolver | |||
]; | |||
} | |||
public function getStatusChoices(): array | |||
public static function getStatusChoices(): array | |||
{ | |||
return [ | |||
TicketModel::TICKET_STATUS_OPEN, | |||
TicketModel::TICKET_STATUS_BEING_PROCESSED, | |||
TicketModel::TICKET_STATUS_PROCESSED, | |||
TicketModel::TICKET_STATUS_CLOSED, | |||
]; | |||
} |
@@ -21,9 +21,9 @@ class TranslatorAdmin | |||
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 |
@@ -35,7 +35,7 @@ class StoreTwigExtension extends AbstractExtension | |||
public function getReminders($params) | |||
{ | |||
//TODO !!!!!! | |||
// @TODO : à faire | |||
return array(); | |||
} | |||
@@ -112,9 +112,9 @@ class TranslatorTwigExtension extends AbstractExtension | |||
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) |
@@ -10,6 +10,7 @@ use Lc\SovBundle\Component\DateComponent; | |||
use Lc\SovBundle\Component\FileComponent; | |||
use Lc\SovBundle\Component\MetaComponent; | |||
use Lc\SovBundle\Component\StringComponent; | |||
use Lc\SovBundle\Doctrine\EntityInterface; | |||
use Lc\SovBundle\Form\Newsletter\NewsletterType; | |||
use Lc\SovBundle\Model\File\FileInterface; | |||
use Lc\SovBundle\Repository\Reminder\ReminderStore; | |||
@@ -96,6 +97,7 @@ class TwigExtension extends AbstractExtension | |||
new TwigFunction('day_by_number', [$this, 'getDayByNumber']), | |||
new TwigFunction('user_current', [$this, 'getUserCurrent']), | |||
new TwigFunction('ea_url_short', [$this, 'generateEaUrl']), | |||
new TwigFunction('is_instance_of', [$this, 'isInstanceOf']), | |||
]; | |||
} | |||
@@ -115,6 +117,20 @@ class TwigExtension extends AbstractExtension | |||
]; | |||
} | |||
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) | |||
{ | |||
$cacheTime = filemtime($this->kernel->getProjectDir() . '/public' . $file); |