浏览代码

Merge branch 'develop'

master
Guillaume 3 年前
父节点
当前提交
ebb567d727
共有 100 个文件被更改,包括 3565 次插入1251 次删除
  1. +42
    -78
      Authenticator/LoginFormAuthenticator.php
  2. +88
    -0
      Builder/Setting/SettingBuilder.php
  3. +91
    -2
      Builder/Ticket/TicketBuilder.php
  4. +67
    -0
      Builder/Ticket/TicketMessageBuilder.php
  5. +40
    -3
      Builder/User/UserBuilder.php
  6. +34
    -0
      Command/SiteSettingInitCommand.php
  7. +5
    -0
      Component/DateComponent.php
  8. +1
    -1
      Component/EntityComponent.php
  9. +9
    -3
      Component/FileComponent.php
  10. +2
    -0
      Component/FormComponent.php
  11. +21
    -0
      Component/NumberComponent.php
  12. +102
    -0
      Container/ComponentContainer.php
  13. +10
    -1
      Container/Newsletter/NewsletterContainer.php
  14. +10
    -1
      Container/Site/NewsContainer.php
  15. +10
    -1
      Container/Site/PageContainer.php
  16. +10
    -1
      Container/Ticket/TicketContainer.php
  17. +10
    -1
      Container/Ticket/TicketMessageContainer.php
  18. +31
    -4
      Container/User/UserContainer.php
  19. +369
    -321
      Controller/AbstractAdminController.php
  20. +10
    -0
      Controller/AbstractController.php
  21. +270
    -0
      Controller/ControllerTrait.php
  22. +4
    -1
      Controller/Dashboard/DashboardAdminController.php
  23. +5
    -0
      Controller/Newsletter/NewsletterAdminController.php
  24. +4
    -2
      Controller/Reminder/ReminderAdminController.php
  25. +38
    -35
      Controller/Security/SecurityAdminController.php
  26. +6
    -19
      Controller/Setting/SettingAdminController.php
  27. +6
    -0
      Controller/Site/NewsAdminController.php
  28. +6
    -0
      Controller/Site/PageAdminController.php
  29. +88
    -104
      Controller/Ticket/TicketAdminController.php
  30. +2
    -2
      Controller/User/AccountAdminController.php
  31. +10
    -4
      Controller/User/GroupUserAdminController.php
  32. +47
    -18
      Controller/User/UserAdminController.php
  33. +21
    -0
      Definition/ActionDefinition.php
  34. +198
    -0
      Definition/Field/AbstractFieldDefinition.php
  35. +45
    -0
      Definition/Field/Newsletter/NewsletterFieldDefinition.php
  36. +58
    -0
      Definition/Field/Site/NewsFieldDefinition.php
  37. +43
    -0
      Definition/Field/Site/PageFieldDefinition.php
  38. +118
    -0
      Definition/Field/Ticket/TicketFieldDefinition.php
  39. +95
    -0
      Definition/Field/User/UserFieldDefinition.php
  40. +7
    -1
      Definition/SiteSettingDefinition.php
  41. +2
    -0
      Doctrine/EntityManager.php
  42. +0
    -27
      Doctrine/Extension/BlameableNullableTrait.php
  43. +39
    -40
      Doctrine/Extension/BlameableTrait.php
  44. +6
    -0
      Doctrine/Extension/SortableTrait.php
  45. +73
    -0
      Event/FormEvent.php
  46. +30
    -0
      Event/Ticket/TicketEvent.php
  47. +12
    -0
      Event/User/UserEvent.php
  48. +0
    -50
      EventSubscriber/FlashMessageAdminEventSubscriber.php
  49. +0
    -109
      EventSubscriber/SiteSettingEventSubscriber.php
  50. +4
    -3
      EventSubscriber/SortablePropertyEventSubscriber.php
  51. +138
    -0
      EventSubscriber/Ticket/SendNotificationTicketEventSubscriber.php
  52. +2
    -0
      Factory/Site/NewsFactory.php
  53. +2
    -0
      Factory/Site/PageFactory.php
  54. +2
    -0
      Factory/User/GroupUserFactory.php
  55. +1
    -1
      Field/BooleanField.php
  56. +39
    -28
      Field/Filter/AssociationFilter.php
  57. +19
    -17
      Field/Filter/CheckboxFilter.php
  58. +26
    -39
      Field/Filter/ChoiceFilter.php
  59. +29
    -31
      Field/Filter/DateFilter.php
  60. +89
    -64
      Field/Filter/FilterManager.php
  61. +13
    -0
      Field/Filter/FilterTrait.php
  62. +57
    -0
      Field/Filter/ImageFilter.php
  63. +7
    -5
      Field/Filter/IntegerFilter.php
  64. +32
    -30
      Field/Filter/TextFilter.php
  65. +38
    -0
      Field/Filter/Ticket/TicketEmailFilter.php
  66. +38
    -0
      Field/Filter/Ticket/TicketFirstnameFilter.php
  67. +38
    -0
      Field/Filter/Ticket/TicketLastnameFilter.php
  68. +3
    -1
      Field/ImageManagerField.php
  69. +4
    -1
      Field/StatusField.php
  70. +22
    -19
      Form/Common/CrudFormType.php
  71. +86
    -74
      Form/Common/FiltersFormType.php
  72. +48
    -0
      Form/Newsletter/NewsletterType.php
  73. +6
    -3
      Form/Setting/BaseSettingType.php
  74. +42
    -35
      Form/Ticket/TicketFormType.php
  75. +7
    -7
      Form/Ticket/TicketMessageAdminFormType.php
  76. +38
    -16
      Form/Ticket/TicketMessageType.php
  77. +2
    -1
      Form/Ticket/TicketStatusType.php
  78. +2
    -0
      Form/User/ChangePasswordFormType.php
  79. +20
    -4
      Form/User/ProfileFormType.php
  80. +1
    -1
      Model/File/FileModel.php
  81. +2
    -2
      Model/Setting/SettingModel.php
  82. +5
    -3
      Model/Site/NewsModel.php
  83. +1
    -2
      Model/Ticket/TicketMessageModel.php
  84. +1
    -4
      Model/Ticket/TicketModel.php
  85. +2
    -6
      Model/User/GroupUserModel.php
  86. +5
    -2
      Model/User/UserModel.php
  87. +124
    -0
      Notification/MailMailjetNotification.php
  88. +101
    -0
      Notification/SmsFactorNotification.php
  89. +32
    -9
      Repository/AbstractRepositoryQuery.php
  90. +19
    -0
      Repository/AbstractStore.php
  91. +206
    -0
      Repository/EntityRepository.php
  92. +1
    -1
      Repository/File/FileRepositoryQuery.php
  93. +1
    -1
      Repository/Newsletter/NewsletterRepositoryQuery.php
  94. +3
    -3
      Repository/Reminder/ReminderRepositoryQuery.php
  95. +3
    -5
      Repository/RepositoryQueryInterface.php
  96. +1
    -1
      Repository/Setting/SiteSettingRepositoryQuery.php
  97. +1
    -1
      Repository/Site/NewsRepositoryQuery.php
  98. +1
    -1
      Repository/Site/PageRepositoryQuery.php
  99. +1
    -1
      Repository/Site/SiteRepositoryQuery.php
  100. +5
    -0
      Repository/Site/SiteStore.php

+ 42
- 78
Authenticator/LoginFormAuthenticator.php 查看文件

@@ -2,107 +2,71 @@

namespace Lc\SovBundle\Authenticator;

use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Repository\User\UserStore;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface as SfUserInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;

public const LOGIN_ROUTE = 'sov_login';

private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
protected $parameterBag;
protected UrlGeneratorInterface $urlGenerator;
protected UserStore $userStore;
protected FormFactoryInterface $formFactory;
protected ParameterBagInterface $parameterBag;

public function __construct(
EntityManager $entityManager,
UrlGeneratorInterface $urlGenerator,
CsrfTokenManagerInterface $csrfTokenManager,
UserPasswordEncoderInterface $passwordEncoder,
ParameterBagInterface $parameterBag
)
{
$this->entityManager = $entityManager;
UrlGeneratorInterface $urlGenerator,
UserStore $userStore,
FormFactoryInterface $formFactory,
ParameterBagInterface $parameterBag
) {
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
$this->userStore = $userStore;
$this->formFactory = $formFactory;
$this->parameterBag = $parameterBag;
}

public function supports(Request $request)
public function supports(Request $request): bool
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getPathInfo();
}

public function getCredentials(Request $request)
public function authenticate(Request $request): PassportInterface
{
$credentials = [
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['email']
$email = $request->request->get('email');
$password = $request->request->get('password');
$csrfToken = $request->request->get('_csrf_token');

return new Passport(
new UserBadge($email, function ($userIdentifier) {
return $this->userStore->getOneByEmail($userIdentifier);
}),
new PasswordCredentials($password),
[new CsrfTokenBadge('authenticate', $csrfToken)]
);

return $credentials;
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}

$user = $this->entityManager->getRepository(UserInterface::class)->findOneBy(
['email' => $credentials['email']]
);

if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Email could not be found.');
}

return $user;
}

public function checkCredentials($credentials, SfUserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}

/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
public function onAuthenticationSuccess(
Request $request,
TokenInterface $token,
string $providerKey
): RedirectResponse {
$routeName = 'home';
$email = $request->request->get('email');
$loginRedirection = $this->parameterBag->get('lc_sov.login_redirection');
@@ -112,7 +76,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
if (isset($useReferer) && $useReferer == true) {
$url = $request->request->get('_target_path');
} else {
$user = $this->entityManager->getRepository(UserInterface::class)->findOneBy(['email' => $email]);
$user = $this->userStore->getOneByEmail($email);

if (!empty($user)) {
$roles = $user->getRoles();
@@ -132,8 +96,8 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
}
}

protected function getLoginUrl()
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
}

+ 88
- 0
Builder/Setting/SettingBuilder.php 查看文件

@@ -0,0 +1,88 @@
<?php

namespace Lc\SovBundle\Builder\Setting;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Definition\SiteSettingDefinition;
use Lc\SovBundle\Factory\Setting\SiteSettingFactory;
use Lc\SovBundle\Repository\Site\SiteStore;
use Lc\SovBundle\Solver\Setting\SettingSolver;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class SettingBuilder
{
protected EntityManagerInterface $entityManager;
protected SettingSolver $settingSolver;
protected SiteStore $siteStore;
protected SiteSettingDefinition $siteSettingDefinition;
protected SiteSettingFactory $siteSettingFactory;

public function __construct(
EntityManagerInterface $entityManager,
SettingSolver $settingSolver,
SiteStore $siteStore,
SiteSettingDefinition $siteSettingDefinition,
SiteSettingFactory $siteSettingFactory
) {
$this->entityManager = $entityManager;
$this->settingSolver = $settingSolver;
$this->siteStore = $siteStore;
$this->siteSettingDefinition = $siteSettingDefinition;
$this->siteSettingFactory = $siteSettingFactory;
}

public function initSiteSettings()
{
$site = $this->siteStore->getOneByDevAlias('default');

if ($site) {
$settings = $this->siteSettingDefinition->getSettings();

foreach ($settings as $category => $settingList) {
foreach ($settingList as $settingName => $setting) {
$entitySetting = $this->settingSolver->getSetting($site, $settingName);

if (!$entitySetting) {
$text = null;
$date = null;
$file = null;

$fieldValue = isset($setting['default']) ? $setting['default'] : null;

if ($setting['field'] == 'text') {
$text = $fieldValue;
}
if ($setting['field'] == 'date') {
$date = $fieldValue;
}
if ($setting['field'] == 'file') {
$file = $fieldValue;
}

$entitySetting = $this->siteSettingFactory->create(
$site,
$setting['name'],
$text,
$date,
$file
);
$this->entityManager->create($entitySetting);
} else {
$methodGetValue = 'get' . ucfirst($setting['field']);
if ($entitySetting->$methodGetValue() === null
&& isset($setting['default'])
&& $setting['default'] !== null) {
$methodSetValue = 'set' . ucfirst($setting['field']);
$entitySetting->$methodSetValue($setting['default']);
$this->entityManager->update($entitySetting);
}
}
}
}

$this->entityManager->flush();
} else {
throw new NotFoundHttpException('Le site par défaut n\'existe pas.');
}
}
}

+ 91
- 2
Builder/Ticket/TicketBuilder.php 查看文件

@@ -2,18 +2,107 @@

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;
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;

class TicketBuilder
{
protected Security $security;
protected EntityManagerInterface $entityManager;
protected MailMailjetNotification $mailMailjetNotification;
protected FormComponent $formComponent;
protected ParameterBagInterface $parameterBag;
protected TicketFactory $ticketFactory;
protected AuthorizationCheckerInterface $authorizationChecker;
protected UserStore $userStore;
protected EventDispatcherInterface $eventDispatcher;

public function __construct(FormComponent $formComponent, ParameterBagInterface $parameterBag)
{

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

public function create(array $params = []): TicketInterface
{
$ticket = $this->ticketFactory->create();

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


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

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

return $ticket;
}

public function init(TicketInterface $ticket, array $params = []): void
{
$user = $this->security->getUser();
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']);
$ticket->setVisitorEmail($params['visitorEmail']);
$ticket->setVisitorToken(uniqid());
}

$ticket
->setStatus(TicketModel::TICKET_STATUS_OPEN)
->setType($params['type'])
->setSubject($params['subject']);

$ticketMessageArray = $ticket->getTicketMessages();
$ticketMessage = $ticketMessageArray[0];
$ticketMessage->setMessage($params['message']);

if (isset($params['imageFilename']) && $params['imageFilename']) {
$ticketMessage->setImageFilename($params['imageFilename']);
}

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

// uploadImageTicketMessage

+ 67
- 0
Builder/Ticket/TicketMessageBuilder.php 查看文件

@@ -0,0 +1,67 @@
<?php

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;
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory;
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,
EventDispatcherInterface $eventDispatcher
) {
$this->entityManager = $entityManager;
$this->mailMailjetNotification = $mailMailjetNotification;
$this->ticketMessageFactory = $ticketMessageFactory;
$this->eventDispatcher = $eventDispatcher;
}

public function create(array $params = []): TicketMessageInterface
{
$ticket = $params['ticket'];
$ticketMessage = $this->ticketMessageFactory->create($ticket);

$ticketMessage->setStatus(1);
$ticketMessage->setTicket($ticket);
$ticketMessage->setMessage($params['message']);
if (isset($params['answerByAdmin']) && $params['answerByAdmin']) {
$ticketMessage->setAnswerByAdmin($params['answerByAdmin']);
}
$this->entityManager->persist($ticketMessage);

if (isset($params['imageFilename']) && $params['imageFilename']) {
$ticketMessage->setImageFilename($params['imageFilename']);
}
if (isset($params['closeTicket']) && $params['closeTicket']) {
$ticket->setStatus(TicketModel::TICKET_STATUS_CLOSED);
}

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

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

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


return $ticketMessage;
}

}

+ 40
- 3
Builder/User/UserBuilder.php 查看文件

@@ -3,16 +3,23 @@
namespace Lc\SovBundle\Builder\User;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\User\UserStore;
use Lc\SovBundle\Solver\User\UserSolver;

class UserBuilder
{
protected EntityManagerInterface $entityManager;

public function __construct(EntityManagerInterface $entityManager)
protected UserStore $userStore;
protected UserSolver $userSolver;
public function __construct(EntityManagerInterface $entityManager, UserStore $userStore, UserSolver $userSolver)
{
$this->entityManager = $entityManager;
$this->userStore = $userStore;
$this->userSolver = $userSolver;
}

public function setNewsletter(UserInterface $user, NewsletterInterface $newsletter, bool $subscribeNewsletter): void
@@ -22,8 +29,38 @@ class UserBuilder
} else {
$user->removeNewsletter($newsletter);
}
$this->entityManager->persist($user);
$this->entityManager->flush();
}

public function initBlameableSystem(EntityInterface $entity)
{
$userSystem = $this->userStore->getOneByDevAlias('system');
$this->initBlameable($entity, $userSystem);

return $entity;
}
public function initBlameableUpdatedSystem(EntityInterface $entity)
{
$userSystem = $this->userStore->getOneByDevAlias('system');
$this->initBlameableUpdated($entity, $userSystem);

return $entity;
}

public function initBlameable(EntityInterface $entity, UserInterface $user)
{
if ($entity instanceof BlameableInterface) {
$entity->setCreatedBy($user);
}
$this->initBlameableUpdated($entity, $user);
}

public function initBlameableUpdated(EntityInterface $entity, UserInterface $user)
{
if ($entity instanceof BlameableInterface) {
$entity->setUpdatedBy($user);
}
}
}

+ 34
- 0
Command/SiteSettingInitCommand.php 查看文件

@@ -0,0 +1,34 @@
<?php

namespace Lc\SovBundle\Command;

use Lc\SovBundle\Builder\Setting\SettingBuilder;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class SiteSettingInitCommand extends Command
{
protected static $defaultName = 'setting:site:init';
protected static $defaultDescription = 'Initialise les SiteSetting.';

protected SettingBuilder $settingBuilder;

public function __construct(string $name = null, SettingBuilder $settingBuilder)
{
parent::__construct($name);
$this->settingBuilder = $settingBuilder;
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->io = new SymfonyStyle($input, $output);
$this->settingBuilder->initSiteSettings();
$this->io->success('Les SiteSetting ont bien été initialisées.');
return Command::SUCCESS;
}
}

+ 5
- 0
Component/DateComponent.php 查看文件

@@ -21,6 +21,11 @@ class DateComponent
}

public function getDayByNumber($number, $lang = 'fr')
{
return self::getDayByNumberStatic($number, $lang);
}

public static function getDayByNumberStatic($number, $lang = 'fr')
{
if ($lang == 'fr') {
$daysArray = [

+ 1
- 1
Component/EntityComponent.php 查看文件

@@ -26,6 +26,7 @@ class EntityComponent

public function duplicateEntity($entity)
{

$newEntity = clone $entity;
$classMetadata = $this->entityManager->getClassMetadata(get_class($newEntity));

@@ -50,7 +51,6 @@ class EntityComponent
}
*/
$this->entityManager->create($newEntity);

$this->eventDispatcher->dispatch(new EntityComponentEvent($newEntity), EntityComponentEvent::DUPLICATE_EVENT);

return $newEntity;

+ 9
- 3
Component/FileComponent.php 查看文件

@@ -3,15 +3,18 @@
namespace Lc\SovBundle\Component;


use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class FileComponent
{
protected ParameterBagInterface $parameterBag;
protected CacheManager $liipCacheHelper;

public function __construct(ParameterBagInterface $parameterBag)
public function __construct(ParameterBagInterface $parameterBag, CacheManager $liipCacheHelper)
{
$this->parameterBag = $parameterBag;
$this->liipCacheHelper = $liipCacheHelper;
}

/**
@@ -27,10 +30,13 @@ class FileComponent
// lcLiip
public function liip($path, $thumb = 'tile', $default = 'default.jpg')
{
if (substr($path, 0, 1) === '/') $path = substr($path, 1);
if (substr($path, 0, 1) === '/') {
$path = substr($path, 1);
}

if ($path) {
$fileManagerFolder = substr($this->getFileManagerFolder(), 1) ;

$fileManagerFolder = substr($this->getFileManagerFolder(), 1);

if (strpos($path, $fileManagerFolder) === false) {
$path = $fileManagerFolder . '/' . $path;

+ 2
- 0
Component/FormComponent.php 查看文件

@@ -6,6 +6,8 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\Validator\Constraints\EqualTo;
use Symfony\Component\Validator\Constraints\NotNull;

class FormComponent
{

+ 21
- 0
Component/NumberComponent.php 查看文件

@@ -10,5 +10,26 @@ class NumberComponent
return round((($price * 100)) / 100, $precision);
}

public function numberToWord(int $number): string
{
$numberWordArray = [
'zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten'
];

if(isset($numberWordArray[$number])) {
return $numberWordArray[$number];
}

return '';
}
}

+ 102
- 0
Container/ComponentContainer.php 查看文件

@@ -0,0 +1,102 @@
<?php

namespace Lc\SovBundle\Container;

use Lc\SovBundle\Component\CitiesComponent;
use Lc\SovBundle\Component\CookieComponent;
use Lc\SovBundle\Component\DateComponent;
use Lc\SovBundle\Component\EntityComponent;
use Lc\SovBundle\Component\FileComponent;
use Lc\SovBundle\Component\FormComponent;
use Lc\SovBundle\Component\MetaComponent;
use Lc\SovBundle\Component\NumberComponent;
use Lc\SovBundle\Component\PointLocationComponent;
use Lc\SovBundle\Component\StringComponent;

class ComponentContainer
{
protected CitiesComponent $citiesComponent;
protected CookieComponent $cookieComponent;
protected DateComponent $dateComponent;
protected EntityComponent $entityComponent;
protected FileComponent $fileComponent;
protected FormComponent $formComponent;
protected MetaComponent $metaComponent;
protected NumberComponent $numberComponent;
protected PointLocationComponent $pointLocationComponent;
protected StringComponent $stringComponent;

public function __construct(
CitiesComponent $citiesComponent,
CookieComponent $cookieComponent,
DateComponent $dateComponent,
EntityComponent $entityComponent,
FileComponent $fileComponent,
FormComponent $formComponent,
MetaComponent $metaComponent,
NumberComponent $numberComponent,
PointLocationComponent $pointLocationComponent,
StringComponent $stringComponent
) {
$this->citiesComponent = $citiesComponent;
$this->cookieComponent = $cookieComponent;
$this->dateComponent = $dateComponent;
$this->entityComponent = $entityComponent;
$this->fileComponent = $fileComponent;
$this->formComponent = $formComponent;
$this->metaComponent = $metaComponent;
$this->numberComponent = $numberComponent;
$this->pointLocationComponent = $pointLocationComponent;
$this->stringComponent = $stringComponent;
}

public function getCitiesComponent(): CitiesComponent
{
return $this->citiesComponent;
}

public function getCookieComponent(): CookieComponent
{
return $this->cookieComponent;
}

public function getDateComponent(): DateComponent
{
return $this->dateComponent;
}

public function getEntityComponent(): EntityComponent
{
return $this->entityComponent;
}

public function getFileComponent(): FileComponent
{
return $this->fileComponent;
}

public function getFormComponent(): FormComponent
{
return $this->formComponent;
}

public function getMetaComponent(): MetaComponent
{
return $this->metaComponent;
}

public function getNumberComponent(): NumberComponent
{
return $this->numberComponent;
}

public function getPointLocationComponent(): PointLocationComponent
{
return $this->pointLocationComponent;
}

public function getStringComponent(): StringComponent
{
return $this->stringComponent;
}
}

+ 10
- 1
Container/Newsletter/NewsletterContainer.php 查看文件

@@ -2,6 +2,7 @@

namespace Lc\SovBundle\Container\Newsletter;

use Lc\SovBundle\Definition\Field\Newsletter\NewsletterFieldDefinition;
use Lc\SovBundle\Factory\Newsletter\NewsletterFactory;
use Lc\SovBundle\Repository\Newsletter\NewsletterRepositoryQuery;
use Lc\SovBundle\Repository\Newsletter\NewsletterStore;
@@ -11,15 +12,18 @@ class NewsletterContainer
protected NewsletterFactory $factory;
protected NewsletterRepositoryQuery $repositoryQuery;
protected NewsletterStore $store;
protected NewsletterFieldDefinition $fieldDefinition;

public function __construct(
NewsletterFactory $factory,
NewsletterRepositoryQuery $repositoryQuery,
NewsletterStore $store
NewsletterStore $store,
NewsletterFieldDefinition $fieldDefinition
) {
$this->factory = $factory;
$this->repositoryQuery = $repositoryQuery;
$this->store = $store;
$this->fieldDefinition = $fieldDefinition;
}

public function getFactory(): NewsletterFactory
@@ -36,4 +40,9 @@ class NewsletterContainer
{
return $this->store;
}

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

+ 10
- 1
Container/Site/NewsContainer.php 查看文件

@@ -2,6 +2,7 @@

namespace Lc\SovBundle\Container\Site;

use Lc\SovBundle\Definition\Field\Site\NewsFieldDefinition;
use Lc\SovBundle\Factory\Site\NewsFactory;
use Lc\SovBundle\Repository\Site\NewsRepositoryQuery;
use Lc\SovBundle\Repository\Site\NewsStore;
@@ -11,15 +12,18 @@ class NewsContainer
protected NewsFactory $factory;
protected NewsRepositoryQuery $repositoryQuery;
protected NewsStore $store;
protected NewsFieldDefinition $fieldDefinition;

public function __construct(
NewsFactory $factory,
NewsRepositoryQuery $repositoryQuery,
NewsStore $store
NewsStore $store,
NewsFieldDefinition $fieldDefinition
) {
$this->factory = $factory;
$this->repositoryQuery = $repositoryQuery;
$this->store = $store;
$this->fieldDefinition = $fieldDefinition;
}

public function getFactory(): NewsFactory
@@ -36,4 +40,9 @@ class NewsContainer
{
return $this->store;
}

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

+ 10
- 1
Container/Site/PageContainer.php 查看文件

@@ -2,6 +2,7 @@

namespace Lc\SovBundle\Container\Site;

use Lc\SovBundle\Definition\Field\Site\PageFieldDefinition;
use Lc\SovBundle\Factory\Site\PageFactory;
use Lc\SovBundle\Repository\Site\PageRepositoryQuery;
use Lc\SovBundle\Repository\Site\PageStore;
@@ -11,15 +12,18 @@ class PageContainer
protected PageFactory $factory;
protected PageRepositoryQuery $repositoryQuery;
protected PageStore $store;
protected PageFieldDefinition $fieldDefinition;

public function __construct(
PageFactory $factory,
PageRepositoryQuery $repositoryQuery,
PageStore $store
PageStore $store,
PageFieldDefinition $fieldDefinition
) {
$this->factory = $factory;
$this->repositoryQuery = $repositoryQuery;
$this->store = $store;
$this->fieldDefinition = $fieldDefinition;
}

public function getFactory(): PageFactory
@@ -36,4 +40,9 @@ class PageContainer
{
return $this->store;
}

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

+ 10
- 1
Container/Ticket/TicketContainer.php 查看文件

@@ -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;
}
}

+ 10
- 1
Container/Ticket/TicketMessageContainer.php 查看文件

@@ -2,6 +2,7 @@

namespace Lc\SovBundle\Container\Ticket;

use Lc\SovBundle\Builder\Ticket\TicketMessageBuilder;
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory;
use Lc\SovBundle\Repository\Ticket\TicketMessageRepositoryQuery;
use Lc\SovBundle\Repository\Ticket\TicketMessageStore;
@@ -11,15 +12,18 @@ class TicketMessageContainer
protected TicketMessageFactory $factory;
protected TicketMessageRepositoryQuery $repositoryQuery;
protected TicketMessageStore $store;
protected TicketMessageBuilder $builder;

public function __construct(
TicketMessageFactory $factory,
TicketMessageRepositoryQuery $repositoryQuery,
TicketMessageStore $store
TicketMessageStore $store,
TicketMessageBuilder $builder
) {
$this->factory = $factory;
$this->repositoryQuery = $repositoryQuery;
$this->store = $store;
$this->builder = $builder;
}

public function getFactory(): TicketMessageFactory
@@ -36,4 +40,9 @@ class TicketMessageContainer
{
return $this->store;
}

public function getBuilder(): TicketMessageBuilder
{
return $this->builder;
}
}

+ 31
- 4
Container/User/UserContainer.php 查看文件

@@ -3,9 +3,12 @@
namespace Lc\SovBundle\Container\User;

use Lc\SovBundle\Builder\User\UserBuilder;
use Lc\SovBundle\Definition\Field\User\UserFieldDefinition;
use Lc\SovBundle\Definition\RolesDefinitionInterface;
use Lc\SovBundle\Factory\User\UserFactory;
use Lc\SovBundle\Repository\User\UserRepositoryQuery;
use Lc\SovBundle\Repository\User\UserStore;
use Lc\SovBundle\Solver\User\UserSolver;

class UserContainer
{
@@ -13,17 +16,26 @@ class UserContainer
protected UserBuilder $builder;
protected UserRepositoryQuery $repositoryQuery;
protected UserStore $store;
protected UserSolver $solver;
protected UserFieldDefinition $fieldDefinition;
protected RolesDefinitionInterface $rolesDefinition;

public function __construct(
UserFactory $factory,
UserBuilder $builder,
UserRepositoryQuery $repositoryQuery,
UserStore $store
UserFactory $factory,
UserBuilder $builder,
UserRepositoryQuery $repositoryQuery,
UserStore $store,
UserSolver $solver,
UserFieldDefinition $fieldDefinition,
RolesDefinitionInterface $rolesDefinition
) {
$this->factory = $factory;
$this->builder = $builder;
$this->repositoryQuery = $repositoryQuery;
$this->store = $store;
$this->solver = $solver;
$this->fieldDefinition = $fieldDefinition;
$this->rolesDefinition = $rolesDefinition;
}

public function getFactory(): UserFactory
@@ -45,4 +57,19 @@ class UserContainer
{
return $this->store;
}

public function getSolver(): UserSolver
{
return $this->solver;
}

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

public function getRoleDefinition(): RolesDefinitionInterface
{
return $this->rolesDefinition;
}
}

+ 369
- 321
Controller/AbstractAdminController.php
文件差异内容过多而无法显示
查看文件


+ 10
- 0
Controller/AbstractController.php 查看文件

@@ -0,0 +1,10 @@
<?php

namespace Lc\SovBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SfAbstractController;

abstract class AbstractController extends SfAbstractController
{
use ControllerTrait;
}

+ 270
- 0
Controller/ControllerTrait.php 查看文件

@@ -0,0 +1,270 @@
<?php

namespace Lc\SovBundle\Controller;

use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Knp\Component\Pager\PaginatorInterface;
use Lc\SovBundle\Component\FileComponent;
use Lc\SovBundle\Container\ComponentContainer;
use Lc\SovBundle\Container\File\FileContainer;
use Lc\SovBundle\Container\Newsletter\NewsletterContainer;
use Lc\SovBundle\Container\Reminder\ReminderContainer;
use Lc\SovBundle\Container\Setting\SiteSettingContainer;
use Lc\SovBundle\Container\Site\NewsContainer;
use Lc\SovBundle\Container\Site\PageContainer;
use Lc\SovBundle\Container\Site\SiteContainer;
use Lc\SovBundle\Container\Ticket\TicketContainer;
use Lc\SovBundle\Container\Ticket\TicketMessageContainer;
use Lc\SovBundle\Container\User\GroupUserContainer;
use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Repository\EntityRepository;
use Lc\SovBundle\Solver\Setting\SettingSolver;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Mailjet\MailjetSwiftMailer\SwiftMailer\MailjetTransport;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;

trait ControllerTrait
{
public static function getSubscribedServices()
{
return array_merge(
parent::getSubscribedServices(),
[
Environment::class => Environment::class,
Security::class => Security::class,
EntityManagerInterface::class => EntityManagerInterface::class,
UrlGeneratorInterface::class => UrlGeneratorInterface::class,
SessionInterface::class => SessionInterface::class,
PaginatorInterface::class => PaginatorInterface::class,
RequestStack::class => RequestStack::class,
EventDispatcherInterface::class => EventDispatcherInterface::class,
LoggerInterface::class => LoggerInterface::class,
ParameterBagInterface::class => ParameterBagInterface::class,
TranslatorInterface::class => TranslatorInterface::class,
TranslatorAdmin::class => TranslatorAdmin::class,
FilterManager::class => FilterManager::class,
FlashBagTranslator::class => FlashBagTranslator::class,
MailjetTransport::class => MailjetTransport::class,
AdminUrlGenerator::class => AdminUrlGenerator::class,
SettingSolver::class => SettingSolver::class,
ComponentContainer::class => ComponentContainer::class,
FileContainer::class => FileContainer::class,
NewsletterContainer::class => NewsletterContainer::class,
ReminderContainer::class => ReminderContainer::class,
NewsContainer::class => NewsContainer::class,
PageContainer::class => PageContainer::class,
SiteContainer::class => SiteContainer::class,
TicketContainer::class => TicketContainer::class,
TicketMessageContainer::class => TicketMessageContainer::class,
GroupUserContainer::class => GroupUserContainer::class,
UserContainer::class => UserContainer::class,
SiteSettingContainer::class => SiteSettingContainer::class,
EntityRepository::class => EntityRepository::class,
FileComponent::class => FileComponent::class,
]
);
}

public function addFlashTranslator(
string $type,
$translationKeyName,
$translationEntityName = null,
$translationParam = array()
): void
{
if ($translationEntityName === null && method_exists($this, 'getTranslationEntityName')) {
$translationEntityName = $this->getTranslationEntityName();
}


$this->get(FlashBagTranslator::class)->add(
$type,
$translationKeyName,
$translationEntityName,
$translationParam
);
}

public function isInstanceOf(string $interfaceName): bool
{
return in_array($interfaceName, class_implements($this->getEntityFqcn()));
}

public function generateEaUrl(string $controller = null, string $action = null, int $entityId = null, array $extraParam = array()): string
{
$adminUrlGenerator = $this->get(AdminUrlGenerator::class);
if ($controller) {
$adminUrlGenerator->setController($controller);
}
if ($action) {
$adminUrlGenerator->setAction($action);
}
if ($entityId) {
$adminUrlGenerator->setEntityId($entityId);
}
if ($extraParam) {
foreach ($extraParam as $key => $value) {
$adminUrlGenerator->set($key, $value);
}
}
return $adminUrlGenerator->generateUrl();
}

public function getReferer(Request $request): ?string
{
return $request->headers->get('referer');
}

public function getTemplating(): Environment
{
return $this->get(Environment::class);
}

public function getEntityManager(): EntityManagerInterface
{
return $this->get(EntityManagerInterface::class);
}

public function getRouter(): UrlGeneratorInterface
{
return $this->get(UrlGeneratorInterface::class);
}

public function getSession(): SessionInterface
{
return $this->get(SessionInterface::class);
}

public function getSecurity(): Security
{
return $this->get(Security::class);
}

public function getPaginator(): PaginatorInterface
{
return $this->get(PaginatorInterface::class);
}

public function getRequestStack(): RequestStack
{
return $this->get(RequestStack::class);
}

public function getEventDispatcher(): EventDispatcherInterface
{
return $this->get(EventDispatcherInterface::class);
}

public function getParameterBag(): ParameterBagInterface
{
return $this->get(ParameterBagInterface::class);
}

public function getTranslator(): TranslatorInterface
{
return $this->get(TranslatorInterface::class);
}

public function getTranslatorAdmin(): TranslatorAdmin
{
return $this->get(TranslatorAdmin::class);
}

public function getLogger(): LoggerInterface
{
return $this->get(LoggerInterface::class);
}

public function getMailjetTransport(): MailjetTransport
{
return $this->get(MailjetTransport::class);
}

public function getAdminUrlGenerator(): AdminUrlGenerator
{
return $this->get(AdminUrlGenerator::class);
}

public function getSettingSolver(): SettingSolver
{
return $this->get(SettingSolver::class);
}

public function getSettingValue($entity, $settingName)
{
return $this->getSettingSolver()->getSettingValue($entity, $settingName);
}

public function getComponentContainer(): ComponentContainer
{
return $this->get(ComponentContainer::class);
}

public function getFileContainer(): FileContainer
{
return $this->get(FileContainer::class);
}

public function getNewsletterContainer(): NewsletterContainer
{
return $this->get(NewsletterContainer::class);
}

public function getReminderContainer(): ReminderContainer
{
return $this->get(ReminderContainer::class);
}

public function getNewsContainer(): NewsContainer
{
return $this->get(NewsContainer::class);
}

public function getPageContainer(): PageContainer
{
return $this->get(PageContainer::class);
}

public function getSiteContainer(): SiteContainer
{
return $this->get(SiteContainer::class);
}

public function getTicketContainer(): TicketContainer
{
return $this->get(TicketContainer::class);
}

public function getTicketMessageContainer(): TicketMessageContainer
{
return $this->get(TicketMessageContainer::class);
}

public function getGroupUserContainer(): GroupUserContainer
{
return $this->get(GroupUserContainer::class);
}

public function getUserContainer(): UserContainer
{
return $this->get(UserContainer::class);
}

public function getSiteSettingContainer(): SiteSettingContainer
{
return $this->get(SiteSettingContainer::class);
}

}

+ 4
- 1
Controller/Dashboard/DashboardAdminController.php 查看文件

@@ -8,6 +8,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Config\UserMenu;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Lc\SovBundle\Controller\ControllerTrait;
use Lc\SovBundle\Doctrine\EntityManager;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\Response;
@@ -16,6 +17,8 @@ use Symfony\Component\Routing\Annotation\Route;
class DashboardAdminController extends AbstractDashboardController
{

use ControllerTrait;

public function index(): Response
{
return $this->render('@LcSov/adminlte/dashboard.html.twig');
@@ -29,7 +32,7 @@ class DashboardAdminController extends AbstractDashboardController
// you can include HTML contents too (e.g. to link to an image)
->setTitle('<img src="assets/img/'.$this->get('parameter_bag')->get('app.admin.logo').'" width="100px">')
// the path defined in this method is passed to the Twig asset() function
->setFaviconPath('favicon.svg')
->setFaviconPath('assets/img/frontend/favicon-pdl.png')
// the domain used by default is 'messages'
->setTranslationDomain('admin');
}

+ 5
- 0
Controller/Newsletter/NewsletterAdminController.php 查看文件

@@ -10,9 +10,14 @@ use Lc\SovBundle\Factory\Newsletter\NewsletterFactory;
use Lc\SovBundle\Field\BooleanField;
use Lc\SovBundle\Field\CKEditorField;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Repository\RepositoryQueryInterface;

abstract class NewsletterAdminController extends AbstractAdminController
{
public function getRepositoryQuery() :RepositoryQueryInterface
{
return $this->get(NewsletterContainer::class)->getRepositoryQuery();
}
public function configureFields(string $pageName): iterable
{
return array_merge(

+ 4
- 2
Controller/Reminder/ReminderAdminController.php 查看文件

@@ -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;
@@ -97,7 +99,7 @@ class ReminderAdminController extends AbstractController
$this->entityManager->persist($reminder);
$this->entityManager->flush();

$this->addFlash('success', 'Le pense-bête a bien été ajouté');
$this->addFlashTranslator('success', 'added');
}

return $this->redirect($request->headers->get('referer'));
@@ -119,7 +121,7 @@ class ReminderAdminController extends AbstractController
$this->entityManager->update($reminder);
$this->entityManager->flush();

$this->addFlash('success', 'Le pense-bête a bien été mis à jour');
$this->addFlashTranslator('success', 'updated');
}

return $this->redirect($request->headers->get('referer'));

+ 38
- 35
Controller/Security/SecurityAdminController.php 查看文件

@@ -3,6 +3,7 @@
namespace Lc\SovBundle\Controller\Security;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
@@ -12,57 +13,57 @@ class SecurityAdminController extends AbstractController
/**
* @Route("/login", name="sov_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
public function login(AuthenticationUtils $authenticationUtils, Request $request): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('app_admin_dashboard');
}
if ($this->getUser()) {
return $this->redirectToRoute('app_admin_dashboard');
}

// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();

return $this->render('@EasyAdmin/page/login.html.twig', [
// parameters usually defined in Symfony login forms
'error' => $error,
'last_username' => $lastUsername,
return $this->render('@EasyAdmin/page/login.html.twig', [
// parameters usually defined in Symfony login forms
'error' => $error,
'last_username' => $lastUsername,

// OPTIONAL parameters to customize the login form:
// OPTIONAL parameters to customize the login form:

// the translation_domain to use (define this option only if you are
// rendering the login template in a regular Symfony controller; when
// rendering it from an EasyAdmin Dashboard this is automatically set to
// the same domain as the rest of the Dashboard)
'translation_domain' => 'admin',
// the translation_domain to use (define this option only if you are
// rendering the login template in a regular Symfony controller; when
// rendering it from an EasyAdmin Dashboard this is automatically set to
// the same domain as the rest of the Dashboard)
'translation_domain' => 'admin',

// the title visible above the login form (define this option only if you are
// rendering the login template in a regular Symfony controller; when rendering
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title)
'page_title' => '<img src="assets/img/'.$this->get('parameter_bag')->get('app.admin.logo').'" >',
// the title visible above the login form (define this option only if you are
// rendering the login template in a regular Symfony controller; when rendering
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title)
'page_title' => '<img src="assets/img/' . $this->get('parameter_bag')->get('app.admin.logo') . '" >',

// the string used to generate the CSRF token. If you don't define
// this parameter, the login form won't include a CSRF token
'csrf_token_intention' => 'authenticate',
// the string used to generate the CSRF token. If you don't define
// this parameter, the login form won't include a CSRF token
'csrf_token_intention' => 'authenticate',

// the URL users are redirected to after the login (default: '/admin')
'target_path' => $this->generateUrl('app_admin_dashboard'),
// the URL users are redirected to after the login (default: '/admin')
'target_path' => $this->generateUrl('app_admin_dashboard'),

// the label displayed for the username form field (the |trans filter is applied to it)
'username_label' => 'Your username',
// the label displayed for the username form field (the |trans filter is applied to it)
'username_label' => 'Your username',

// the label displayed for the password form field (the |trans filter is applied to it)
'password_label' => 'Your password',
// the label displayed for the password form field (the |trans filter is applied to it)
'password_label' => 'Your password',

// the label displayed for the Sign In form button (the |trans filter is applied to it)
'sign_in_label' => 'Log in',
// the label displayed for the Sign In form button (the |trans filter is applied to it)
'sign_in_label' => 'Log in',

// the 'name' HTML attribute of the <input> used for the username field (default: '_username')
'username_parameter' => 'email',
// the 'name' HTML attribute of the <input> used for the username field (default: '_username')
'username_parameter' => 'email',

// the 'name' HTML attribute of the <input> used for the password field (default: '_password')
'password_parameter' => 'password',
]);
// the 'name' HTML attribute of the <input> used for the password field (default: '_password')
'password_parameter' => 'password',
]);
}

/**
@@ -70,6 +71,8 @@ class SecurityAdminController extends AbstractController
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
throw new \LogicException(
'This method can be blank - it will be intercepted by the logout key on your firewall.'
);
}
}

+ 6
- 19
Controller/Setting/SettingAdminController.php 查看文件

@@ -2,34 +2,21 @@

namespace Lc\SovBundle\Controller\Setting;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Container\Setting\SiteSettingContainer;
use Lc\SovBundle\Container\Site\SiteContainer;
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface;
use Lc\SovBundle\Controller\AbstractController;
use Lc\SovBundle\Form\Setting\SiteSettingsFormType;
use Lc\SovBundle\Repository\Setting\SiteSettingRepository;
use Lc\SovBundle\Repository\Site\SiteRepository;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class SettingAdminController extends AbstractController
{
protected EntityManagerInterface $entityManager;

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

/**
* @Route("/admin/setting/site", name="sov_admin_setting_site")
*/
public function manageGlobal(Request $request, EntityManagerInterface $entityManager)
public function manageGlobal(Request $request)
{
$site = $this->get(SiteContainer::class)->getStore()->getOneByDevAlias('default') ;
$entityManager = $this->getEntityManager();
$site = $this->getSiteContainer()->getStore()->getOneByDevAlias('default') ;
$form = $this->createForm(SiteSettingsFormType::class, $site);

$form->handleRequest($request);
@@ -39,7 +26,7 @@ class SettingAdminController extends AbstractController
$entityManager->update($site);
$entityManager->flush();

$this->addFlash('success', $this->get(TranslatorAdmin::class)->transFlashMessage('settings_saved'));
$this->addFlashTranslator('success', 'updated');
}

return $this->render(
@@ -51,4 +38,4 @@ class SettingAdminController extends AbstractController
);
}

}
}

+ 6
- 0
Controller/Site/NewsAdminController.php 查看文件

@@ -11,10 +11,16 @@ use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Factory\Site\NewsFactory;
use Lc\SovBundle\Field\CKEditorField;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Repository\RepositoryQueryInterface;

abstract class NewsAdminController extends AbstractAdminController
{

public function getRepositoryQuery() :RepositoryQueryInterface
{
return $this->get(NewsContainer::class)->getRepositoryQuery();
}

public function configureFields(string $pageName): iterable
{
$panel = parent::configureFields($pageName);

+ 6
- 0
Controller/Site/PageAdminController.php 查看文件

@@ -10,10 +10,16 @@ use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Factory\Site\PageFactory;
use Lc\SovBundle\Field\CKEditorField;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Repository\RepositoryQueryInterface;

abstract class PageAdminController extends AbstractAdminController
{

public function getRepositoryQuery() :RepositoryQueryInterface
{
return $this->get(PageContainer::class)->getRepositoryQuery();
}

public function configureFields(string $pageName): iterable
{
$panel = parent::configureFields($pageName);

+ 88
- 104
Controller/Ticket/TicketAdminController.php 查看文件

@@ -3,128 +3,107 @@
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\Registry\TemplateRegistry;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Lc\SovBundle\Container\Ticket\TicketContainer;
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\Container\Ticket\TicketMessageContainer;
use Lc\SovBundle\Definition\ActionDefinition;
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\Translation\TranslatorAdmin;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;

class TicketAdminController extends AbstractAdminController
abstract class TicketAdminController extends AbstractAdminController
{

public static function getEntityFqcn(): string
public function getRepositoryQuery(): RepositoryQueryInterface
{
return TicketInterface::class;
return $this->getTicketContainer()->getRepositoryQuery();
}

public function createEntity(string $entityFqcn)
{
return $this->get(TicketContainer::class)->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'));
$crud->overrideTemplate('crud/detail', '@LcSov/admin/ticket/detail.html.twig');
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/username.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, Action::DETAIL)
->remove(Crud::PAGE_INDEX, Action::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)
{
@@ -132,20 +111,20 @@ 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(TicketContainer::class)->getFactory()->create();
$formAddTicketMessage = $this->createForm(TicketMessageFormType::class, $ticketMessage);
$ticketMessage = $this->get(TicketMessageContainer::class)->getFactory()->create($ticket);
$formAddTicketMessage = $this->createForm(TicketMessageAdminFormType::class, $ticketMessage);
$formAddTicketMessage->handleRequest($this->get(RequestStack::class)->getMainRequest());

if ($formAddTicketMessage->isSubmitted() && $formAddTicketMessage->isValid()) {
@@ -154,31 +133,36 @@ 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,
]
$context->getTemplatePath('crud/detail'),
[
'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
- 2
Controller/User/AccountAdminController.php 查看文件

@@ -40,7 +40,7 @@ class AccountAdminController extends AbstractController
$this->entityManager->update($user);
$this->entityManager->flush();

$this->addFlash('success', new TranslatableMessage('form.account_profile.message.success', [], 'admin'));
$this->addFlashTranslator('success', 'updated');
}

return $this->render(
@@ -71,7 +71,7 @@ class AccountAdminController extends AbstractController
$this->entityManager->update($user);
$this->entityManager->flush();

$this->addFlash('success', new TranslatableMessage('form.account_password.message.success', [], 'admin'));
$this->addFlashTranslator('success', 'passwordUpdated');
}

return $this->render(

+ 10
- 4
Controller/User/GroupUserAdminController.php 查看文件

@@ -5,21 +5,27 @@ namespace Lc\SovBundle\Controller\User;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Container\User\GroupUserContainer;
use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Factory\User\GroupUserFactory;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Repository\RepositoryQueryInterface;

abstract class GroupUserAdminController extends AbstractAdminController
{
public function getRepositoryQuery(): RepositoryQueryInterface
{
return $this->get(GroupUserContainer::class)->getRepositoryQuery();
}

public function configureFields(string $pageName): iterable
{
return [
TextField::new('title'),
TextField::new('devAlias'),
TextField::new('title')->setSortable(true),
TextField::new('devAlias')->hideOnIndex(),
StatusField::new('status')->setSortable(true),
];
}

public function createEntity(string $entityFqcn)
{
return $this->get(GroupUserContainer::class)->getFactory()->create();
return $this->getGroupUserContainer()->getFactory()->create();
}
}

+ 47
- 18
Controller/User/UserAdminController.php 查看文件

@@ -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;
@@ -17,29 +22,53 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;

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 configureFields(string $pageName): iterable
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
{
return [
EmailField::new('email'),
TextField::new('lastname'),
TextField::new('firstname'),
ChoiceField::new('roles')
->allowMultipleChoices()
->autocomplete()
->setChoices($this->rolesDefinition->getRolesList())
EmailField::new('email'),
TextField::new('lastname'),
TextField::new('firstname'),
ChoiceField::new('roles')
->allowMultipleChoices()
->autocomplete()
->setChoices($this->getUserContainer()->getRoleDefinition()->getRolesList())
];
}


+ 21
- 0
Definition/ActionDefinition.php 查看文件

@@ -0,0 +1,21 @@
<?php
namespace Lc\SovBundle\Definition;

class ActionDefinition {
public const BATCH_DELETE = 'batchDelete';
public const DELETE = 'delete';
public const DETAIL = 'detail';
public const EDIT = 'edit';
public const INDEX = 'index';
public const NEW = 'new';
public const DUPLICATE = 'duplicate';
public const SORT = 'sort';
public const INDEX_CHILDREN = 'index_children';
public const INDEX_PARENT = 'index_parent';
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';

}

+ 198
- 0
Definition/Field/AbstractFieldDefinition.php 查看文件

@@ -0,0 +1,198 @@
<?php

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;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\ImageManagerField;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\TextType;

abstract class AbstractFieldDefinition
{
protected TranslatorAdmin $translatorAdmin;

public function __construct(TranslatorAdmin $translatorAdmin)
{
$this->translatorAdmin = $translatorAdmin;
}

abstract public function configureFields(): array;

public function configureFieldsBase(): array
{
return [
'id' => IntegerField::new('id')->onlyOnIndex()->setSortable(true),
'metaTitle' => TextField::new('metaTitle')
->setLabel('Meta : title')
->setHelp('Affiché dans les résultats de recherche Google'),
'metaDescription' => TextareaField::new('metaDescription')
->setLabel('Meta : description')
->setHelp('Affiché dans les résultats de recherche Google'),
'openGraphTitle' => TextField::new('openGraphTitle')
->setLabel('OpenGraph : titre'),
'openGraphDescription' => TextareaField::new('openGraphDescription')
->setLabel('OpenGraph : description'),
'openGraphImage' => ImageManagerField::new('openGraphImage')
->setLabel('OpenGraph : image'),
'oldUrls' => CollectionField::new('oldUrls')
->setFormTypeOption('entry_type', TextType::class)
->setLabel('Anciennes urls du document')
->hideOnIndex(),
'devAlias' => TextField::new('devAlias')->hideOnIndex(),
'status' => StatusField::new('status')->setSortable(true),
'createdAt' => DateTimeField::new('createdAt')->setSortable(true),
'updatedAt' => DateTimeField::new('updatedAt')->setSortable(true),
];
}

public function configureDefaultFields(): array
{
return array_keys($this->configureFields());
}

public function configureIndex(): array
{
return $this->configureDefaultFields();
}

public function configureDetail(): array
{
return $this->configureDefaultFields();
}

public function configureForm(): array
{
return $this->configureDefaultFields();
}

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

public function configurePanelSeo(): array
{
return [
'metaTitle',
'metaDescription',
'oldUrls'
];
}

public function configurePanelOpengraph(): array
{
return [
'openGraphTitle',
'openGraphDescription',
'openGraphImage'
];
}

public function configurePanelConf(): array
{
return [
'devAlias',
];
}

public function getFields(string $pageName = ''): array
{
if($pageName == Crud::PAGE_INDEX) {
return $this->buildFieldArray($this->configureIndex());
}
elseif($pageName == Crud::PAGE_DETAIL) {
return $this->buildFieldArray($this->configureDetail());
}
elseif($pageName == Crud::PAGE_EDIT || $pageName == Crud::PAGE_NEW) {
return $this->buildFieldArrayForm();
}

return [];
}

public function getAllFields(): array
{
return array_merge(
$this->configureFieldsBase(),
$this->configureFields(),
);
}

public function getFieldsByPanel(string $panel): array
{
return $this->buildFieldArrayFormByPanel($panel);
}

protected function buildFieldArray(array $configureFieldArray): array
{
$allFieldArray = $this->getAllFields();

$fieldArray = [];
foreach($configureFieldArray as $fieldName) {
if(isset($allFieldArray[$fieldName])) {
$fieldArray[] = $allFieldArray[$fieldName];
}
else {
throw new \ErrorException('Le field "'.$fieldName.'" n\'est pas défini dans configureFields()');
}
}

return $fieldArray;
}

protected function buildFieldArrayForm(): array
{
$fieldArray = [];
$panelArray = $this->configurePanels();

if($panelArray && count($panelArray) > 0) {
foreach($panelArray as $panel) {
$fieldArray = array_merge(
$fieldArray,
$this->buildFieldArrayFormByPanel($panel)
);
}
}
else {
$fieldArray = $this->buildFieldArray($this->configureForm());
}

return $fieldArray;
}

protected function buildFieldArrayFormByPanel(string $panel): array
{
$method = 'configurePanel' . ucfirst($panel);
if(method_exists($this, $method)) {
$panelFieldArray = $this->$method();
}
else{
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 => $fieldPanel

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

}

+ 45
- 0
Definition/Field/Newsletter/NewsletterFieldDefinition.php 查看文件

@@ -0,0 +1,45 @@
<?php

namespace Lc\SovBundle\Definition\Field\Newsletter;

use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\SovBundle\Field\BooleanField;
use Lc\SovBundle\Field\CKEditorField;

class NewsletterFieldDefinition extends AbstractFieldDefinition
{
public function configureIndex(): array
{
return [
'id',
'title',
'isMain',
'status'
];
}

public function configurePanels(): array
{
return ['main', 'seo', 'conf'];
}

public function configurePanelMain(): array
{
return [
'title',
'description',
'status'
];
}

public function configureFields(): array
{
return [
'title' => TextField::new('title'),
'description' => CKEditorField::new('description')->hideOnIndex(),
'isMain' => BooleanField::new('isMain')->setCustomOption('toggle_label', 'Principale'),
];
}

}

+ 58
- 0
Definition/Field/Site/NewsFieldDefinition.php 查看文件

@@ -0,0 +1,58 @@
<?php

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\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
{
public function configureIndex(): array
{
return [
'id',
'title',
'status'
];
}

public function configurePanels(): array
{
return ['main', 'seo', 'opengraph', 'conf'];
}

public function configurePanelMain(): array
{
return [
'date',
'title',
'newsletter',
'image',
'description',
'isSent',
'status'
];
}

public function configureFields(): array
{
return [
'date' => DateField::new('date')
->setFormat('d/MM/y')
->setSortable(true),
'title' => TextField::new('title')->setSortable(true),
'newsletter' => AssociationField::new('newsletter')->setSortable(true),
'image' => ImageManagerField::new('image'),
'position' => NumberField::new('position'),
'description' => CKEditorField::new('description'),
'isSent' => BooleanField::new('isSent')->setSortable(true),
];
}

}

+ 43
- 0
Definition/Field/Site/PageFieldDefinition.php 查看文件

@@ -0,0 +1,43 @@
<?php

namespace Lc\SovBundle\Definition\Field\Site;

use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\SovBundle\Field\CKEditorField;

class PageFieldDefinition extends AbstractFieldDefinition
{

public function configureIndex(): array
{
return [
'id',
'title',
'status'
];
}

public function configurePanelMain(): array
{
return [
'title',
'description',
'status'
];
}

public function configurePanels(): array
{
return ['main', 'seo', 'conf'];
}

public function configureFields(): array
{
return [
'title' => TextField::new('title')->setSortable(true),
'description' => CKEditorField::new('description')->hideOnIndex(),
];
}

}

+ 118
- 0
Definition/Field/Ticket/TicketFieldDefinition.php 查看文件

@@ -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',
'updatedAt',
'visitorFirstname',
'visitorLastname',
'visitorEmail',
'subject',
'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)
];
}

}

+ 95
- 0
Definition/Field/User/UserFieldDefinition.php 查看文件

@@ -0,0 +1,95 @@
<?php

namespace Lc\SovBundle\Definition\Field\User;


use EasyCorp\Bundle\EasyAdminBundle\Field\ArrayField;
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 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;

class UserFieldDefinition extends AbstractFieldDefinition
{
protected RolesDefinition $rolesDefinition;

public function __construct(TranslatorAdmin $translatorAdmin, RolesDefinition $rolesDefinition)
{
parent::__construct($translatorAdmin);

$this->rolesDefinition = $rolesDefinition;
}

public function configureFieldsIndex(): array
{
return [
'id',
'gender',
'lastname',
'firstname',
'email',
'groupUsers'
];
}

public function configureFieldsForm(): array
{
return [
'id',
'gender',
'lastname',
'firstname',
'email',
'phone',
'birthdate',
'groupUsers',
'ticketTypesNotification'
];
}

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

public function configureFields(): array
{
return [
'id' => IntegerField::new('id')->onlyOnIndex()->setSortable(true),
'gender' => ChoiceField::new('gender')->setChoices(
$this->translatorAdmin->transChoices(UserSolver::getGenderChoices(), 'User', 'gender')
)
->setFormTypeOption('expanded', true)
->setFormTypeOption('multiple', false)
->setSortable(true),
'lastname' => TextField::new('lastname')->setSortable(true),
'firstname' => TextField::new('firstname')->setSortable(true),
'email' => TextField::new('email')->setSortable(true),
'phone' => TextField::new('phone')->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()
->setChoices($this->rolesDefinition->getRolesList()),
];
}

}

+ 7
- 1
Definition/SiteSettingDefinition.php 查看文件

@@ -6,12 +6,18 @@ namespace Lc\SovBundle\Definition;
class SiteSettingDefinition extends AbstractSettingDefinition implements SiteSettingDefinitionInterface
{
const CATEGORY_GENERAL = 'general';
const CATEGORY_EMAIL = 'email';

const SETTING_MAINTENANCE = 'maintenance';
const SETTING_MAINTENANCE_IP_AUTHORIZED = 'maintenanceIpAuthorized';

const SETTING_EMAIL_SUBJECT_PREFIX = 'emailSubjectPrefix';
const SETTING_EMAIL_FROM = 'emailFrom';
const SETTING_EMAIL_FROM_NAME = 'emailFromName';

public function __construct()
{
// général
$this->addSettingSelect(
[
'category' => self::CATEGORY_GENERAL,
@@ -34,7 +40,7 @@ class SiteSettingDefinition extends AbstractSettingDefinition implements SiteSet
public function getCategories()
{
return [
self::CATEGORY_GENERAL
self::CATEGORY_GENERAL,
];
}


+ 2
- 0
Doctrine/EntityManager.php 查看文件

@@ -5,7 +5,9 @@ namespace Lc\SovBundle\Doctrine;
use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\ORM\EntityManager as DoctrineEntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**

+ 0
- 27
Doctrine/Extension/BlameableNullableTrait.php 查看文件

@@ -1,27 +0,0 @@
<?php

namespace Lc\SovBundle\Doctrine\Extension;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Lc\SovBundle\Model\User\UserInterface;

trait BlameableNullableTrait
{

/**
* @Gedmo\Blameable(on="create")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=true)
*/
protected $createdBy;

/**
* @Gedmo\Blameable(on="update")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=true)
*/
protected $updatedBy;


}

+ 39
- 40
Doctrine/Extension/BlameableTrait.php 查看文件

@@ -9,43 +9,42 @@ use Lc\SovBundle\Model\User\UserInterface;
trait BlameableTrait
{

/**
* @Gedmo\Blameable(on="create")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=false)
*/
protected $createdBy;

/**
* @Gedmo\Blameable(on="update")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=false)
*/
protected $updatedBy;


public function getCreatedBy(): ?UserInterface
{
return $this->createdBy;
}

public function setCreatedBy(?UserInterface $createdBy): self
{
$this->createdBy = $createdBy;

return $this;
}

public function getUpdatedBy(): ?UserInterface
{
return $this->updatedBy;
}

public function setUpdatedBy(?UserInterface $updatedBy): self
{
$this->updatedBy = $updatedBy;

return $this;
}

}
/**
* @Gedmo\Blameable(on="create")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=true)
*/
protected $createdBy;

/**
* @Gedmo\Blameable(on="update")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=true)
*/
protected $updatedBy;


public function getCreatedBy(): ?UserInterface
{
return $this->createdBy;
}

public function setCreatedBy(?UserInterface $createdBy): self
{
$this->createdBy = $createdBy;

return $this;
}

public function getUpdatedBy(): ?UserInterface
{
return $this->updatedBy;
}

public function setUpdatedBy(?UserInterface $updatedBy): self
{
$this->updatedBy = $updatedBy;

return $this;
}
}

+ 6
- 0
Doctrine/Extension/SortableTrait.php 查看文件

@@ -31,4 +31,10 @@ trait SortableTrait
$this->position = $position;
return $this;
}

public function clearPosition(): self
{
$this->position = null;
return $this;
}
}

+ 73
- 0
Event/FormEvent.php 查看文件

@@ -0,0 +1,73 @@
<?php

/*
* This file is part of the FOSUserBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Lc\SovBundle\Event;

use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\Event;

class FormEvent extends Event
{
/**
* @var FormInterface
*/
private $form;

/**
* @var Request
*/
private $request;

/**
* @var Response
*/
private $response;

/**
* FormEvent constructor.
*/
public function __construct(FormInterface $form, Request $request)
{
$this->form = $form;
$this->request = $request;
}

/**
* @return FormInterface
*/
public function getForm()
{
return $this->form;
}

/**
* @return Request
*/
public function getRequest()
{
return $this->request;
}

public function setResponse(Response $response)
{
$this->response = $response;
}

/**
* @return Response|null
*/
public function getResponse()
{
return $this->response;
}
}

+ 30
- 0
Event/Ticket/TicketEvent.php 查看文件

@@ -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;
}
}

+ 12
- 0
Event/User/UserEvent.php 查看文件

@@ -0,0 +1,12 @@
<?php

namespace Lc\SovBundle\Event\User;

use Lc\SovBundle\Event\FormEvent;

class UserEvent extends FormEvent
{
const REGISTRATION_SUCCESS = 'user.registration.success';
const REGISTRATION_FAILURE = 'user.registration.failure';

}

+ 0
- 50
EventSubscriber/FlashMessageAdminEventSubscriber.php 查看文件

@@ -1,50 +0,0 @@
<?php

namespace Lc\SovBundle\EventSubscriber;

use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityPersistedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Translation\TranslatableMessage;

class FlashMessageAdminEventSubscriber implements EventSubscriberInterface
{
protected $session ;

public function __construct(SessionInterface $session)
{
$this->session = $session ;
}

public static function getSubscribedEvents(): array
{
return [
AfterEntityPersistedEvent::class => ['flashMessageAfterPersist'],
AfterEntityUpdatedEvent::class => ['flashMessageAfterUpdate'],
AfterEntityDeletedEvent::class => ['flashMessageAfterDelete'],
];
}

public function flashMessageAfterPersist(AfterEntityPersistedEvent $event): void
{
$this->session->getFlashBag()->add('success', new TranslatableMessage('flash_message.create', [
'%name%' => (string) $event->getEntityInstance(),
]));
}

public function flashMessageAfterUpdate(AfterEntityUpdatedEvent $event): void
{
$this->session->getFlashBag()->add('success', new TranslatableMessage('flash_message.update', [
'%name%' => (string) $event->getEntityInstance(),
]));
}

public function flashMessageAfterDelete(AfterEntityDeletedEvent $event): void
{
$this->session->getFlashBag()->add('success', new TranslatableMessage('flash_message.delete', [
'%name%' => (string) $event->getEntityInstance(),
]));
}
}

+ 0
- 109
EventSubscriber/SiteSettingEventSubscriber.php 查看文件

@@ -1,109 +0,0 @@
<?php

namespace Lc\SovBundle\EventSubscriber;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface;
use Lc\SovBundle\Factory\Setting\SiteSettingFactory;
use Lc\SovBundle\Factory\Site\SiteFactory;
use Lc\SovBundle\Repository\Setting\SiteSettingRepository;
use Lc\SovBundle\Repository\Site\SiteRepository;
use Lc\SovBundle\Repository\Site\SiteStore;
use Lc\SovBundle\Solver\Setting\SettingSolver;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;

class SiteSettingEventSubscriber implements EventSubscriberInterface
{
protected EntityManagerInterface $entityManager;
protected SiteSettingDefinitionInterface $siteSettingDefinition;
protected SiteSettingFactory $siteSettingFactory;
protected SiteSettingRepository $siteSettingRepository;
protected SiteStore $siteStore;
protected SiteFactory $siteFactory;
protected SettingSolver $settingSolver;

public function __construct(
EntityManagerInterface $entityManager,
SiteSettingRepository $siteSettingRepository,
SiteStore $siteStore,
SiteSettingDefinitionInterface $siteSettingDefinition,
SiteSettingFactory $siteSettingFactory,
SiteFactory $siteFactory,
SettingSolver $settingSolver
) {
$this->entityManager = $entityManager;
$this->siteSettingDefinition = $siteSettingDefinition;
$this->siteSettingFactory = $siteSettingFactory;
$this->siteSettingRepository = $siteSettingRepository;
$this->siteStore = $siteStore;
$this->siteFactory = $siteFactory;
$this->settingSolver = $settingSolver;
}

public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER => ['initSettings']
];
}

public function initSettings()
{
$site = $this->getSiteDefault();
if (!$site) {
$site = $this->siteFactory->create('default');
$this->entityManager->persist($site);
$this->entityManager->flush($site);
}

$settings = $this->siteSettingDefinition->getSettings();
$factory = $this->siteSettingFactory;

foreach ($settings as $category => $settingList) {
foreach ($settingList as $settingName => $setting) {
$entitySetting = $this->settingSolver->getSetting($site, $settingName);

if (!$entitySetting) {

$text = null;
$date = null;
$file = null;

$fieldValue = isset($setting['default']) ? $setting['default'] : null;

if($setting['field'] == 'text') {
$text = $fieldValue;
}
if($setting['field'] == 'date') {
$date = $fieldValue;
}
if($setting['field'] == 'file') {
$file = $fieldValue;
}

$entitySetting = $factory->create($site, $setting['name'], $text, $date, $file);

$this->entityManager->persist($entitySetting);
} else {
$methodGetValue = 'get' . ucfirst($setting['field']);
if ($entitySetting->$methodGetValue() === null
&& isset($setting['default'])
&& $setting['default'] !== null) {
$methodSetValue = 'set' . ucfirst($setting['field']);
$entitySetting->$methodSetValue($setting['default']);
$this->entityManager->update($entitySetting);
}
}
}
}

$this->entityManager->flush();
}

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

}

+ 4
- 3
EventSubscriber/SortablePropertyEventSubscriber.php 查看文件

@@ -41,14 +41,15 @@ class SortablePropertyEventSubscriber implements EventSubscriberInterface

private function setSortableProperty(EntityInterface $entity, AbstractRepositoryInterface $entityRepository)
{
$countParam = array();
if ($entity instanceof StatusInterface) {
$countParam['status'] = 1;
}

if ($entity instanceof TreeInterface) {
if($entity->getParent()){
if ($entity->getParent()) {
$countParam['parent'] = $entity->getParent()->getId();
}else{
} else {
$countParam['parent'] = null;
}
}
@@ -59,4 +60,4 @@ class SortablePropertyEventSubscriber implements EventSubscriberInterface
}


}
}

+ 138
- 0
EventSubscriber/Ticket/SendNotificationTicketEventSubscriber.php 查看文件

@@ -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],
],
]
);
}
}
}


}

+ 2
- 0
Factory/Site/NewsFactory.php 查看文件

@@ -12,6 +12,8 @@ class NewsFactory extends AbstractFactory implements NewsFactoryInterface
{
$news = new News();

$news->setStatus(1);

return $news;
}


+ 2
- 0
Factory/Site/PageFactory.php 查看文件

@@ -12,6 +12,8 @@ class PageFactory extends AbstractFactory implements PageFactoryInterface
{
$page = new Page();

$page->setStatus(1);

return $page;
}
}

+ 2
- 0
Factory/User/GroupUserFactory.php 查看文件

@@ -12,6 +12,8 @@ class GroupUserFactory extends AbstractFactory implements GroupUserFactoryInterf
{
$groupUser = new GroupUser();

$groupUser->setStatus(1);

return $groupUser;
}
}

+ 1
- 1
Field/BooleanField.php 查看文件

@@ -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);
}


+ 39
- 28
Field/Filter/AssociationFilter.php 查看文件

@@ -3,8 +3,8 @@
namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;

@@ -18,49 +18,60 @@ class AssociationFilter

public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$param = array();
$targetEntity = $options['entity_dto']->getPropertyMetadata($fieldDto->getProperty())->get('targetEntity');

$classImplements = class_implements($targetEntity);
if ($fieldDto->getCustomOption('choices')) {
$choices = $fieldDto->getCustomOption('choices');
} elseif ($fieldDto->getFormTypeOption('choices') != null) {
$choices = $fieldDto->getFormTypeOption('choices');
} else {
$choices = array();
}

if ($fieldDto->getFormTypeOption('choice_label') != null) {
$param['choice_label'] = $fieldDto->getFormTypeOption('choice_label');
}
//todo utiliser choices plutot que query_builder voir ProductCategoriesFilter
$builder->add(
$fieldDto->getProperty(),
EntityType::class,
array(
'class' => $targetEntity,
'placeholder' => '--',
'query_builder' => function (EntityRepository $repo) use ($classImplements) {
return $repo->createQueryBuilder('entity');
},
'required' => false,
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),
array_merge(
$param,
array(
'class' => $targetEntity,
'placeholder' => '--',
'choices' => $choices,
'required' => false,
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),


)
)
);
}

public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue = null)
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);
if ($filteredValue !== null) {
$queryBuilder->andWhere('entity.'.$fieldProperty.' = :'.$fieldProperty.'');
$queryBuilder->setParameter($fieldProperty, $filteredValue);
/* //TODO Faut généraliser avec TreeInterface, ça ne doit pas être ici
if ($field['property'] == 'productCategories') {

$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ' OR product_categories.parent = :' . $field['property']);
$queryBuilder->setParameter($field['property'], $filter);
if ($fieldDto->getFormTypeOption('multiple')) {
$repositoryQuery->andWhere(':' . $fieldProperty . ' MEMBER OF .' . $fieldProperty . '');
} else {
$repositoryQuery->andWhere('.' . $fieldProperty . ' = :' . $fieldProperty . '');
}
$repositoryQuery->setParameter($fieldProperty, $filteredValue);

if ($field['type_options']['multiple']) {
$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . '');
} else {
}

if ($filter instanceof TreeInterface && $filter->getParent() == null) {
$queryBuilder->setParameter($field['property'], array_merge(array($filter), $filter->getChildrens()->toArray()));
} else {
}*/
//
// if ($filter instanceof TreeInterface && $filter->getParent() == null) {
// $repositoryQuery->setParameter($field['property'], array_merge(array($filter), $filter->getChildrens()->toArray()));
// } else {
// }
}
}


+ 19
- 17
Field/Filter/CheckboxFilter.php 查看文件

@@ -2,8 +2,9 @@

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -34,28 +35,29 @@ class CheckboxFilter
));
}

public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null)
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, string $filteredValue= null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);
if ($filteredValue !== null) {
if ($this->isRelationField($fieldProperty)) {
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty);
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) {
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation);
}
$queryBuilder->andWhere(
$fieldProperty.' = :'.$this->getFieldPropertySnake($fieldProperty).''
);
$queryBuilder->setParameter(
$this->getFieldPropertySnake($fieldProperty),
'%'.$filteredValue.'%'
);
// $aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty);
// if (array_search($aliasRelation, $repositoryQuery->getAllAliases()) === false) {
// $repositoryQuery->innerJoin('entity.'.$aliasRelation, $aliasRelation);
// }
// $repositoryQuery->andWhere(
// $fieldProperty.' = :'.$this->getFieldPropertySnake($fieldProperty).''
// );
// $repositoryQuery->setParameter(
// $this->getFieldPropertySnake($fieldProperty),
// $filteredValue
// );
} else {
$queryBuilder->andWhere(
'entity.'.$fieldProperty.' = :'.$fieldProperty.''
$repositoryQuery->andWhere(
'.'.$fieldProperty.' = :'.$fieldProperty.''
);
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%');
$repositoryQuery->setParameter($fieldProperty, $filteredValue);
}
dump($queryBuilder);
}
}


+ 26
- 39
Field/Filter/ChoiceFilter.php 查看文件

@@ -2,8 +2,9 @@

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -27,50 +28,36 @@ class ChoiceFilter

public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$entity = new $options['entity_class'];
$choicesFct = 'get'.u($fieldDto->getProperty())->title()->toString().'Choices';

if (method_exists($entity, $choicesFct)) {
$builder->add(
$fieldDto->getProperty(),
ChoiceType::class,
array(
'required' => false,
'choices' => $this->translatorAdmin->transChoices(
$entity->$choicesFct(),
$options['entity_name'],
$fieldDto->getProperty()
),
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),
)
if($fieldDto->getCustomOption('choices')){
$choices = $fieldDto->getCustomOption('choices');
}else if($fieldDto->getFormTypeOption('choices') !=null){
$choices = $fieldDto->getFormTypeOption('choices');
}else{
$choices = array();
}
$builder->add(
$fieldDto->getProperty(),
ChoiceType::class,
array(
'required' => false,
'choices' => $choices,
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),
)
);
}
}

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

}
}


+ 29
- 31
Field/Filter/DateFilter.php 查看文件

@@ -2,8 +2,9 @@

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -18,46 +19,43 @@ class DateFilter
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$builder->add(
$builder->create(
str_replace('.', '_', $fieldDto->getProperty()),
FormType::class,
array('inherit_data' => true)
$builder->create(
str_replace('.', '_', $fieldDto->getProperty()),
FormType::class,
array('inherit_data' => true)
)
->add(
'dateStart',
DateType::class,
array(
'widget' => 'single_text',
'required' => false,
)
)
->add(
'dateStart',
DateType::class,
array(
'widget' => 'single_text',
'required' => false,
)
)
->add(
'dateEnd',
DateType::class,
array(
'widget' => 'single_text',
'required' => false,
->add(
'dateEnd',
DateType::class,
array(
'widget' => 'single_text',
'required' => false,

)
)
)
)
);
}

public function applyFilter(
QueryBuilder $queryBuilder,
string $fieldProperty,
\DateTime $dateStart = null,
\DateTime $dateEnd = null
) {
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, \DateTime $dateStart = null, \DateTime $dateEnd = null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);
if ($dateStart) {
$queryBuilder->andWhere(
'entity.'.$fieldProperty.' >= :dateStart'
$repositoryQuery->andWhere(
'.' . $fieldProperty . ' >= :dateStart'
)->setParameter('dateStart', $dateStart);
}
if ($dateEnd) {
$dateEnd->setTime(23, 59, 59);
$queryBuilder->andWhere(
'entity.'.$fieldProperty.' <= :dateEnd'
$repositoryQuery->andWhere(
'.' . $fieldProperty . ' <= :dateEnd'
)->setParameter('dateEnd', $dateEnd);
}
}

+ 89
- 64
Field/Filter/FilterManager.php 查看文件

@@ -3,17 +3,22 @@
namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;

use DoctrineExtensions\Query\Mysql\Field;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\RequestStack;
@@ -26,19 +31,24 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
class FilterManager
{
protected $em;
protected bool $isFiltered = false;
protected $translatorAdmin;

use FilterTrait;

public function __construct(SessionInterface $session, EntityManagerInterface $entityManager)
public function __construct(SessionInterface $session, EntityManagerInterface $entityManager, TranslatorAdmin $translatorAdmin)
{
$this->session = $session;
$this->em = $entityManager;
$this->translatorAdmin = $translatorAdmin;
}


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

foreach ($fields as $field) {
$filteredValue = array();
if ($field instanceof FieldInterface) {
$fieldDto = $field->getAsDto();
} else {
@@ -47,79 +57,97 @@ class FilterManager
if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX)) {
if ($filtersForm->has($this->getFieldPropertySnake($fieldDto->getProperty()))) {



if ($fieldDto->getFormType() === DateTimeType::class || $fieldDto->getFormType(
) === DateType::class) {
if ($fieldDto->getFormType() === DateTimeType::class || $fieldDto->getFormType() === DateType::class) {
$filteredValue['dateStart'] = $this->getFilteredValue(
$filtersForm,
$entityDto->getFqcn(),
$fieldDto->getProperty(),
'dateStart'
$filtersForm,
$entityDto->getFqcn(),
$fieldDto->getProperty(),
'dateStart'
);
$filteredValue['dateEnd'] = $this->getFilteredValue(
$filtersForm,
$entityDto->getFqcn(),
$fieldDto->getProperty(),
'dateEnd'
$filtersForm,
$entityDto->getFqcn(),
$fieldDto->getProperty(),
'dateEnd'
);
}else{
$filteredValue = $this->getFilteredValue(
$filtersForm,
$entityDto->getFqcn(),
$fieldDto->getProperty()
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($queryBuilder, $fieldDto, $filteredValue);

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

public function applyFilter(QueryBuilder $queryBuilder, FieldDto $fieldDto, $filteredValue)

public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, array $filteredValue)
{
switch ($fieldDto->getFormType()) {
case CheckboxType::class:
$checkboxFilter = new CheckboxFilter();
$checkboxFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue);
break;
case ChoiceType::class:
$choiceFilter = new ChoiceFilter();
$choiceFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue);
break;
case IntegerType::class:
$integerFilter = new IntegerFilter();
$integerFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue);
break;
case TextType::class:
$textFilter = new TextFilter();
$textFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue);
break;
case EntityType::class:
$textFilter = new AssociationFilter();
$textFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue);
break;
case DateTimeType::class:
case DateType::class:
$textFilter = new DateFilter();
$textFilter->applyFilter(
$queryBuilder,
$fieldDto->getProperty(),
if ($fieldDto->getCustomOption('filter_fqcn')) {
$filterFqcn = $fieldDto->getCustomOption('filter_fqcn');
$customFilter = new $filterFqcn($this->translatorAdmin);

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

switch ($fieldDto->getFormType()) {

case CheckboxType::class:
$checkboxFilter = new CheckboxFilter();
$checkboxFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
break;
case ChoiceType::class:
$choiceFilter = new ChoiceFilter();
$choiceFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
break;
case IntegerType::class:
$integerFilter = new IntegerFilter();
$integerFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
break;
case TextareaType::class:
case TextType::class:
case EmailType::class:
$textFilter = new TextFilter();
$textFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
break;
case EntityType::class:
$textFilter = new AssociationFilter();
$textFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
break;
case DateTimeType::class:
case DateType::class:
$textFilter = new DateFilter();
$textFilter->applyFilter(
$repositoryQuery,
$fieldDto,
$filteredValue['dateStart'],
$filteredValue['dateEnd']
);
break;
);
break;
}
}
}

public function getFilteredValue(
Form $filtersForm,
string $entityFqcn,
string $field,
string $dateExtraField = null
) {
Form $filtersForm,
string $entityFqcn,
string $field,
string $dateExtraField = null
)
{
$field = $this->getFieldPropertySnake($field);
$sessionParam = $entityFqcn.$field.$dateExtraField;
$sessionParam = $entityFqcn . $field . $dateExtraField;

$formField = $this->getFormField($filtersForm, $field, $dateExtraField);

@@ -147,7 +175,7 @@ class FilterManager
//Champ association
} elseif ($formField->getConfig()->getOption('class')) {
$valFormated = $this->em->getRepository(
$formField->getConfig()->getOption('class')
$formField->getConfig()->getOption('class')
)->find($value);
$filtersForm->get($field)->setData($valFormated);
} else {
@@ -160,16 +188,13 @@ class FilterManager

}

public
function getFormField(
Form $filtersForm,
string $field,
string $extraField = null
): Form {
public function getFormField(Form $filtersForm, string $field, string $extraField = null): Form
{
if ($extraField) {
return $filtersForm->get($field)->get($extraField);
} else {
return $filtersForm->get($field);
}
}

}

+ 13
- 0
Field/Filter/FilterTrait.php 查看文件

@@ -3,6 +3,8 @@
namespace Lc\SovBundle\Field\Filter;


use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;

/**
* @author La clic ! <contact@laclic.fr>
*/
@@ -34,4 +36,15 @@ trait FilterTrait
return substr($fieldName, 0, strpos($fieldName, $needle));
}


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

}

+ 57
- 0
Field/Filter/ImageFilter.php 查看文件

@@ -0,0 +1,57 @@
<?php

namespace Lc\SovBundle\Field\Filter;


use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @author La clic ! <contact@laclic.fr>
*/
class ImageFilter
{
use FilterTrait;

public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$targetEntity = $options['entity_dto']->getPropertyMetadata($fieldDto->getProperty())->get('targetEntity');

$builder->add(
$fieldDto->getProperty(),
ChoiceType::class,
array(
'required' => false,
'choices' => array(
'Sans image' => 0,
'Avec image' => 1,
),
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),
)
);
}


public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);
if ($filteredValue !== null) {
if($filteredValue === 1){
$repositoryQuery->andWhere(
'.' . $fieldProperty . ' IS NOT NULL'
);
}else{
$repositoryQuery->andWhere(
'.' . $fieldProperty . ' IS NULL'
);
}

}
}

}

+ 7
- 5
Field/Filter/IntegerFilter.php 查看文件

@@ -2,8 +2,9 @@

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormBuilderInterface;

@@ -30,13 +31,14 @@ class IntegerFilter
);
}

public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null)
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, string $filteredValue= null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);
if ($filteredValue !== null) {
$queryBuilder->andWhere(
'entity.'.$fieldProperty.' = :'.$fieldProperty.''
$repositoryQuery->andWhere(
'.'.$fieldProperty.' = :'.$fieldProperty.''
);
$queryBuilder->setParameter($fieldProperty, $filteredValue);
$repositoryQuery->setParameter($fieldProperty, $filteredValue);
}
}


+ 32
- 30
Field/Filter/TextFilter.php 查看文件

@@ -2,8 +2,9 @@

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

@@ -15,44 +16,45 @@ class TextFilter
use FilterTrait;


public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$builder->add(
str_replace('.', '_', $fieldDto->getProperty()),
TextType::class,
array(
'required' => false,
'attr' => array(
'class' => ' input-sm',
'form' => 'filters-form',
),
)
str_replace('.', '_', $fieldDto->getProperty()),
TextType::class,
array(
'required' => false,
'attr' => array(
'class' => ' input-sm',
'form' => 'filters-form',
),
)
);
}

public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null)
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, string $filteredValue = null)
{
$fieldProperty = $this->getFieldProperty($fieldDto);

if ($filteredValue !== null) {
if ($this->isRelationField($fieldProperty)) {

$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty);
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) {
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation);
}
$queryBuilder->andWhere(
$fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).''
);
$queryBuilder->setParameter(
$this->getFieldPropertySnake($fieldProperty),
'%'.$filteredValue.'%'
// 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 . ''
);
} else {
$queryBuilder->andWhere(
'entity.'.$fieldProperty.' LIKE :'.$fieldProperty.''
);
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%');
}
$repositoryQuery->setParameter($fieldProperty, '%' . $filteredValue . '%');

}
}


+ 38
- 0
Field/Filter/Ticket/TicketEmailFilter.php 查看文件

@@ -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.'%');
}
}

}

+ 38
- 0
Field/Filter/Ticket/TicketFirstnameFilter.php 查看文件

@@ -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.'%');
}
}

}

+ 38
- 0
Field/Filter/Ticket/TicketLastnameFilter.php 查看文件

@@ -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.'%');
}
}

}

+ 3
- 1
Field/ImageManagerField.php 查看文件

@@ -4,6 +4,7 @@ namespace Lc\SovBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Lc\SovBundle\Field\Filter\ImageFilter;
use Lc\SovBundle\Form\Common\FileManagerType;

/**
@@ -28,7 +29,8 @@ final class ImageManagerField implements FieldInterface
->setCustomOption('type', 'image')
->addCssClass('field-text')
->setCustomOption(self::OPTION_MAX_LENGTH, null)
->setCustomOption(self::OPTION_RENDER_AS_HTML, false);
->setCustomOption(self::OPTION_RENDER_AS_HTML, false)
->setCustomOption('filter_fqcn', ImageFilter::class);
}

public function setMaxLength(int $length): self

+ 4
- 1
Field/StatusField.php 查看文件

@@ -4,6 +4,8 @@ namespace Lc\SovBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Lc\SovBundle\Field\Filter\BooleanFilter;
use Lc\SovBundle\Field\Filter\CheckboxFilter;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

/**
@@ -23,7 +25,8 @@ final class StatusField implements FieldInterface
->setFormTypeOption('multiple', false)
->setFormTypeOption('choices', ['En ligne' => 1, 'Hors ligne' => 0])
->setFormTypeOption('placeholder', false)
->setCustomOption('toggle_label', 'En ligne');
->setCustomOption('toggle_label', 'En ligne')
->setCustomOption('filter_fqcn', CheckboxFilter::class);

$template = 'toggle.html.twig';
if (!$templateToggle) {

+ 22
- 19
Form/Common/CrudFormType.php 查看文件

@@ -9,14 +9,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Custom form type that deals with some of the logic used to render the
* forms used to create and edit EasyAdmin entities.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
class CrudFormType extends AbstractType
{

@@ -27,20 +22,17 @@ class CrudFormType extends AbstractType
DoctrineOrmTypeGuesser $doctrineOrmTypeGuesser,
\EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudFormType $crudFormType
) {

$this->parent = $crudFormType;
$this->doctrineOrmTypeGuesser = $doctrineOrmTypeGuesser;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{

$this->parent->buildForm($builder, $options);
$entityDto = $options['entityDto'];
$formPanels = [];
$currentFormPanel = 0;
foreach ($entityDto->getFields() as $fieldDto) {

if (null === $formFieldType = $fieldDto->getFormType()) {
$guessType = $this->doctrineOrmTypeGuesser->guessType($entityDto->getFqcn(), $fieldDto->getProperty());
$formFieldType = $guessType->getType();
@@ -49,30 +41,41 @@ class CrudFormType extends AbstractType

if (EaFormPanelType::class === $formFieldType) {
++$currentFormPanel;
$formPanels[$currentFormPanel] = [
'form_tab' => $currentFormTab ?? null,
'label' => $fieldDto->getLabel(),
'help' => $fieldDto->getHelp(),
'css_class' => $fieldDto->getCssClass(),
];
foreach ($fieldDto->getCustomOptions()->all() as $customOptionKey => $customOption) {
$formPanels[$currentFormPanel][$customOptionKey] = $customOption;
if($fieldDto->getLabel()) {
$formPanels[$currentFormPanel] = [
'form_tab' => null,
'label' => $fieldDto->getLabel(),
'help' => $fieldDto->getHelp(),
'css_class' => $fieldDto->getCssClass(),
];
foreach ($fieldDto->getCustomOptions()->all() as $customOptionKey => $customOption) {
$formPanels[$currentFormPanel][$customOptionKey] = $customOption;
}
}
continue;
}
}

$builder->setAttribute('ea_form_panels', $formPanels);
//$this->niche->buildForm($builder, $options);
}

public function finishView(FormView $view, FormInterface $form, array $options)
{
$view->vars['translation_entity_name'] = $options['translation_entity_name'];

$this->parent->finishView($view, $form, $options);
}

public function configureOptions(OptionsResolver $resolver)
{
$this->parent->configureOptions($resolver);
$resolver->setDefaults(
[
'translation_entity_name' => static function (Options $options, $dataClass) {
return $dataClass ?? $options['entityDto']->getFqcn();
}
]
);

}

public function getBlockPrefix()

+ 86
- 74
Form/Common/FiltersFormType.php 查看文件

@@ -2,33 +2,30 @@

namespace Lc\SovBundle\Form\Common;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Field\Filter\AssociationFilter;
use Lc\SovBundle\Field\Filter\CheckboxFilter;
use Lc\SovBundle\Field\Filter\ChoiceFilter;
use Lc\SovBundle\Field\Filter\DateFilter;
use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Field\Filter\IntegerFilter;
use Lc\SovBundle\Field\Filter\TextFilter;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
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\Contracts\Translation\TranslatorInterface;

use function Symfony\Component\String\u;

@@ -51,73 +48,79 @@ class FiltersFormType extends AbstractType
} else {
$fieldDto = $field;
}
if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX)) {
switch ($fieldDto->getFormType()) {
case CheckboxType::class:
$checkboxFilter = new CheckboxFilter();
$checkboxFilter->buildProperty($builder, $fieldDto);

break;
case ChoiceType::class:
$choiceFilter = new ChoiceFilter($this->translatorAdmin);
$choiceFilter->buildProperty($builder, $fieldDto, $options);
break;
case IntegerType::class:
$integerFilter = new IntegerFilter();
$integerFilter->buildProperty($builder, $fieldDto);
//POurt modifier le type de filtre filter_type
//Pour désactiver le filtre sur un champ filter à false

break;
case TextType::class:
$textFilter = new TextFilter();
$textFilter->buildProperty($builder, $fieldDto);
break;
case DateTimeType::class:
case DateType::class:
$textFilter = new DateFilter();
$textFilter->buildProperty($builder, $fieldDto);
break;
case EntityType::class:
$associationFilter = new AssociationFilter();
$associationFilter->buildProperty($builder, $fieldDto, $options);
break;
case 'dateinterval':
if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX) && $fieldDto->getCustomOption('filter')!==false) {
if($fieldDto->getCustomOption('filter_fqcn')){
$filterFqcn = $fieldDto->getCustomOption('filter_fqcn');
$checkboxFilter = new $filterFqcn($this->translatorAdmin);
$checkboxFilter->buildProperty($builder, $fieldDto, $options);
}else {

break;
case 'float':
switch ($this->guessFormType($fieldDto)) {
case CheckboxType::class:
$checkboxFilter = new CheckboxFilter();
$checkboxFilter->buildProperty($builder, $fieldDto);
break;
case ChoiceType::class:
$choiceFilter = new ChoiceFilter($this->translatorAdmin);
$choiceFilter->buildProperty($builder, $fieldDto, $options);
break;
case IntegerType::class:
$integerFilter = new IntegerFilter();
$integerFilter->buildProperty($builder, $fieldDto);

break;
break;
case TextType::class:
case EmailType::class:
case TextareaType::class:
$textFilter = new TextFilter();
$textFilter->buildProperty($builder, $fieldDto);
break;
case DateTimeType::class:
case DateType::class:
$textFilter = new DateFilter();
$textFilter->buildProperty($builder, $fieldDto);
break;
case EntityType::class:
$associationFilter = new AssociationFilter();
$associationFilter->buildProperty($builder, $fieldDto, $options);
break;
}
}
}
}
$builder->add(
'action_apply',
SubmitType::class,
array(
'label_html'=> true,
'label'=> '<i class="fa fa-search"></i>',
'attr' => array(
'class' => 'btn btn-sm btn-info',
'form' => 'filters-form',
'data-toggle'=>"tooltip",
'title'=> $this->translatorAdmin->transAction("apply"),
'aria-label'=> $this->translatorAdmin->transAction("apply")
),
)
'action_apply',
SubmitType::class,
array(
'label_html' => true,
'label' => '<i class="fa fa-search"></i>',
'attr' => array(
'class' => 'btn btn-sm btn-info',
'form' => 'filters-form',
'data-toggle' => "tooltip",
'title' => $this->translatorAdmin->transAction("apply"),
'aria-label' => $this->translatorAdmin->transAction("apply")
),
)
);
$builder->add(
'action_reset',
ButtonType::class,
array(
'label_html'=> true,
'label'=> '<i class="fa fa-eraser"></i>',
'attr' => array(
'class' => 'btn btn-sm btn-warning lc-reset-filters',
'form' => 'filters-form',
'data-toggle'=>"tooltip",
'title'=> $this->translatorAdmin->transAction("reset"),
'aria-label'=> $this->translatorAdmin->transAction("reset")
),
)
'action_reset',
SubmitType::class,
array(
'label_html' => true,
'label' => '<i class="fa fa-eraser"></i>',
'attr' => array(
'class' => 'btn btn-sm btn-warning lc-reset-filters',
'form' => 'filters-form',
'data-toggle' => "tooltip",
'title' => $this->translatorAdmin->transAction("reset"),
'aria-label' => $this->translatorAdmin->transAction("reset")
),
)
);
$builder->add('reset', HiddenType::class);
}
@@ -125,16 +128,25 @@ class FiltersFormType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'label' => false,
'csrf_protection' => false,
'entity_dto' => null,
//'translation_domain' => 'lcshop',
'fields' => false,
'entity_name' => false,
'entity_class' => false,
//'entityClass' => false
]
[
'label' => false,
'csrf_protection' => false,
'entity_dto' => null,
//'translation_domain' => 'lcshop',
'fields' => false,
'entity_name' => false,
'entity_class' => false,
//'entityClass' => false
]
);
}
}

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

}
}

+ 48
- 0
Form/Newsletter/NewsletterType.php 查看文件

@@ -0,0 +1,48 @@
<?php

namespace Lc\SovBundle\Form\Newsletter;

use Lc\SovBundle\Component\FormComponent;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotNull;

class NewsletterType extends AbstractType
{
protected FormComponent $formComponent;

public function __construct(FormComponent $formComponent)
{
$this->formComponent = $formComponent;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'email',
EmailType::class,
[
'label' => 'Renseignez votre adresse email :',
'constraints' => [
new Email(),
new NotNull()
]
]
);

// captcha
$this->formComponent->addCaptchaType($builder);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[

]
);
}
}

+ 6
- 3
Form/Setting/BaseSettingType.php 查看文件

@@ -15,8 +15,8 @@ use Symfony\Component\Form\Extension\Core\Type\TimeType;

abstract class BaseSettingType extends AbstractType
{
protected $em;
protected $settingDefinition;
protected EntityManagerInterface $em;
protected SiteSettingDefinitionInterface $settingDefinition;

public function __construct(
EntityManagerInterface $entityManager,
@@ -53,7 +53,10 @@ abstract class BaseSettingType extends AbstractType
'text',
CKEditorType::class,
[
'label' => $label
'label' => $label,
'attr' => [
'class' => 'field-text_editor'
]
]
);
} elseif ($settingType == 'select') {

+ 42
- 35
Form/Ticket/TicketFormType.php 查看文件

@@ -6,6 +6,7 @@ use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketModel;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Solver\Ticket\TicketSolver;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
@@ -18,57 +19,63 @@ use Symfony\Component\OptionsResolver\OptionsResolver;

class TicketFormType extends AbstractType
{
protected $em;
protected $translatorAdmin;
protected EntityManager $entityManager;
protected TranslatorAdmin $translatorAdmin;

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

public function buildForm(FormBuilderInterface $builder, array $options)
{
$entityName = $this->em->getEntityName(TicketInterface::class);
$entityName = $this->entityManager->getEntityName(TicketInterface::class);

$builder->add(
'user',
EntityType::class,
[
'class' => $this->em->getEntityName(UserInterface::class),
]
'user',
EntityType::class,
[
'class' => $this->entityManager->getEntityName(UserInterface::class),
]
);

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

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

$builder->add(
'ticketMessages',
CollectionType::class,
[
'entry_type' => TicketMessageType::class,
'allow_add' => false,
'label_attr' => ['class' => 'label-ticket'],
]
'ticketMessages',
CollectionType::class,
[
'entry_type' => TicketMessageType::class,
'allow_add' => false,
'label_attr' => ['class' => 'label-ticket'],
]
);

$builder->add(
'submit',
SubmitType::class,
[
'label' => $this->translatorAdmin->transAction('save')
]
'submit',
SubmitType::class,
[
'label' => $this->translatorAdmin->transAction('save')
]
);
}

@@ -78,9 +85,9 @@ class TicketFormType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => $this->em->getEntityName(TicketInterface::class),
]
[
'data_class' => $this->entityManager->getEntityName(TicketInterface::class),
]
);
}
}
}

Form/Ticket/TicketMessageFormType.php → Form/Ticket/TicketMessageAdminFormType.php 查看文件

@@ -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
]
);
}


+ 38
- 16
Form/Ticket/TicketMessageType.php 查看文件

@@ -2,39 +2,61 @@

namespace Lc\SovBundle\Form\Ticket;

use Lc\SovBundle\Doctrine\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
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\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\File;

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

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

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'message',
TextareaType::class,
[
'required' => true
]
);
$builder
->add('message', TextareaType::class, [
'label' => 'entity.TicketMessage.fields.message',
'translation_domain' => 'admin',
])
->add('image', FileType::class, [
'label' => 'Photo',
'mapped' => false,
'required' => false,
'constraints' => [
new File([
'maxSize' => '2048k',
'mimeTypes' => [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
],
'mimeTypesMessage' => "Mauvais format d'image (formats acceptés : jpeg, png, gif)",
])
],
])
->add('closeTicket', CheckboxType::class, [
'label' => 'entity.TicketMessage.fields.closeTicket',
'translation_domain' => 'admin',
'required' => false,
'mapped' => false,
]);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => $this->em->getEntityName(TicketMessageInterface::class),
]
);
$resolver->setDefaults([
'data_class' => $this->entityManager->getEntityName(TicketMessageInterface::class),
]);
}
}

+ 2
- 1
Form/Ticket/TicketStatusType.php 查看文件

@@ -3,6 +3,7 @@
namespace Lc\SovBundle\Form\Ticket;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Solver\Ticket\TicketSolver;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
@@ -29,7 +30,7 @@ class TicketStatusType extends AbstractType
'status',
ChoiceType::class,
[
'choices' => $this->translatorAdmin->transChoices(TicketModel::getStatusChoices(),'Ticket', 'status'),
'choices' => $this->translatorAdmin->transChoices(TicketSolver::getStatusChoices(),'Ticket', 'status'),
'required' => true,
'expanded' => true,
'label' => false,

+ 2
- 0
Form/User/ChangePasswordFormType.php 查看文件

@@ -54,6 +54,7 @@ class ChangePasswordFormType extends AbstractType
PasswordType::class,
[
'label' => 'form.account_password.field.current_password',
'translation_domain' => 'admin',
'mapped' => false,
'constraints' => [
new NotBlank(),
@@ -71,6 +72,7 @@ class ChangePasswordFormType extends AbstractType
'first_options' => ['label' => 'form.account_password.field.new_password'],
'second_options' => ['label' => 'form.account_password.field.new_password_repeat'],
'invalid_message' => $this->translatorAdmin->trans('form.account_password.message.invalid_passwords'),
'translation_domain' => 'admin',
]
);
}

+ 20
- 4
Form/User/ProfileFormType.php 查看文件

@@ -32,23 +32,39 @@ class ProfileFormType extends AbstractType

$builder->add(
'firstname',
TextType::class
TextType::class,
[
'label' => 'entity.default.fields.firstname',
'translation_domain' => 'admin',
]
);

$builder->add(
'lastname',
TextType::class
TextType::class,
[
'label' => 'entity.default.fields.lastname',
'translation_domain' => 'admin',
]
);

$builder->add(
'email',
EmailType::class
EmailType::class,
[
'label' => 'entity.default.fields.email',
'translation_domain' => 'admin',
]
);

if (property_exists($entityName, 'phone')) {
$builder->add(
'phone',
TextType::class
TextType::class,
[
'label' => 'entity.default.fields.phone',
'translation_domain' => 'admin',
]
);
}
}

+ 1
- 1
Model/File/FileModel.php 查看文件

@@ -39,7 +39,7 @@ abstract class FileModel implements SortableInterface, BlameableInterface, Times


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

public function getPath(): ?string

+ 2
- 2
Model/Setting/SettingModel.php 查看文件

@@ -11,7 +11,7 @@ use Lc\SovBundle\Model\File\FileInterface;
abstract class SettingModel implements SettingInterface
{
/**
* @ORM\Column(type="string", length=63)
* @ORM\Column(type="string", length=63, nullable=true)
*/
protected $name;

@@ -35,7 +35,7 @@ abstract class SettingModel implements SettingInterface
return $this->name;
}

public function setName(string $name): self
public function setName(?string $name): self
{
$this->name = $name;


+ 5
- 3
Model/Site/NewsModel.php 查看文件

@@ -4,6 +4,8 @@ namespace Lc\SovBundle\Model\Site;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
use Lc\SovBundle\Doctrine\Extension\OpenGraphTrait;
use Lc\SovBundle\Doctrine\Pattern\AbstractFullEntity;
use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
@@ -11,8 +13,9 @@ use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
/**
* @ORM\MappedSuperclass()
*/
abstract class NewsModel extends AbstractFullEntity implements NewsInterface
abstract class NewsModel extends AbstractFullEntity implements NewsInterface, OpenGraphInterface
{
use OpenGraphTrait;

/**
* @ORM\Column(type="datetime")
@@ -25,9 +28,8 @@ abstract class NewsModel extends AbstractFullEntity implements NewsInterface
*/
protected $isSent;


/**
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\Newsletter\NewsletterInterface", inversedBy="news")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\Newsletter\NewsletterInterface")
*/
protected $newsletter;


+ 1
- 2
Model/Ticket/TicketMessageModel.php 查看文件

@@ -16,7 +16,6 @@ use Lc\SovBundle\Doctrine\Pattern\AbstractLightEntity;
abstract class TicketMessageModel extends AbstractLightEntity implements TicketMessageInterface, EntityInterface, StatusInterface
{
use StatusTrait;
use BlameableNullableTrait;

/**
* @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

+ 1
- 4
Model/Ticket/TicketModel.php 查看文件

@@ -16,14 +16,13 @@ use Lc\SovBundle\Model\User\UserInterface;
*/
abstract class TicketModel extends AbstractLightEntity implements TicketInterface, EntityInterface
{
use BlameableNullableTrait;


const TYPE_TECHNICAL_PROBLEM = 'technical-problem';
const TYPE_GENERAL_QUESTION = 'general-question';

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

/**
@@ -94,7 +93,6 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
return $this;
}


public function getStatus(): ?string
{
return $this->status;
@@ -107,7 +105,6 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
return $this;
}


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

+ 2
- 6
Model/User/GroupUserModel.php 查看文件

@@ -6,19 +6,15 @@ use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Doctrine\Pattern\AbstractFullEntity;
use Lc\SovBundle\Doctrine\Pattern\AbstractLightEntity;

/**
* @ORM\MappedSuperclass()
*/
abstract class GroupUserModel extends AbstractLightEntity implements GroupUserInterface, EntityInterface
abstract class GroupUserModel extends AbstractFullEntity implements GroupUserInterface, EntityInterface
{

/**
* @ORM\Column(type="string", length=255)
*/
protected $title;

/**
* @ORM\ManyToMany(targetEntity="Lc\SovBundle\Model\User\UserInterface", mappedBy="groupUsers")
*/

+ 5
- 2
Model/User/UserModel.php 查看文件

@@ -8,7 +8,7 @@ use Doctrine\ORM\Mapping as ORM;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\DevAliasTrait;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
use Lc\SovBundle\Doctrine\Extension\TimestampableTrait;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Symfony\Component\Security\Core\User\UserInterface;

@@ -18,6 +18,8 @@ use Symfony\Component\Security\Core\User\UserInterface;
abstract class UserModel implements EntityInterface, UserInterface, DevAliasInterface
{
use DevAliasTrait;
use TimestampableTrait;

/**
* @ORM\Column(type="string", length=180, unique=true)
*/
@@ -48,6 +50,7 @@ abstract class UserModel implements EntityInterface, UserInterface, DevAliasInte
* @ORM\Column(type="string", length=20, nullable=true)
*/
protected $phone;

/**
* @ORM\Column(type="boolean", nullable=true)
*/
@@ -131,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;


+ 124
- 0
Notification/MailMailjetNotification.php 查看文件

@@ -0,0 +1,124 @@
<?php

namespace Lc\SovBundle\Notification;

use Lc\SovBundle\Definition\SiteSettingDefinition;
use Lc\SovBundle\Repository\Site\SiteStore;
use Lc\SovBundle\Solver\Setting\SettingSolver;
use Mailjet\MailjetSwiftMailer\SwiftMailer\MailjetTransport;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Twig\Environment;

class MailMailjetNotification
{
const SUBJECT = 'subject';
const SUBJECT_PREFIX = 'subject-prefix';
const TO_EMAIL = 'to-email';
const COPY_TO = 'copy-to';
const COPY_HIDDEN_TO = 'copy-hidden-to';
const TO_NAME = 'to-name';
const FROM_EMAIL = 'from-email';
const FROM_NAME = 'from-name';
const REPLY_TO = 'reply-to';
const CONTENT_TEMPLATE = 'content-template';
const CONTENT_DATA = 'content-data';
const ATTACHMENT_DATA = 'attachment-data';
const ATTACHMENT_FILENAME = 'attachment-filename';
const ATTACHMENT_CONTENT_TYPE = 'attachment-content-type';

protected MailjetTransport $transport;
protected Environment $templating;
protected ParameterBagInterface $parameterBag;
protected SettingSolver $settingSolver;
protected SiteStore $siteStore;

public function __construct(
MailjetTransport $mailjetTransport,
Environment $templating,
ParameterBagInterface $parameterBag,
SettingSolver $settingSolver,
SiteStore $siteStore
) {
$this->transport = $mailjetTransport;
$this->templating = $templating;
$this->parameterBag = $parameterBag;
$this->settingSolver = $settingSolver;
$this->siteStore = $siteStore;
}

public function send($params = [])
{
$siteDefault = $this->siteStore->getOneDefault();

$emailSubjectPrefix = (isset($params[self::SUBJECT_PREFIX]) && $params[self::SUBJECT_PREFIX] && strlen($params[self::SUBJECT_PREFIX]) > 0)
? $params[self::SUBJECT_PREFIX]
: $this->settingSolver->getSettingValue(
$siteDefault,
SiteSettingDefinition::SETTING_EMAIL_SUBJECT_PREFIX
);

$emailFrom = (isset($params[self::FROM_EMAIL]) && $params[self::FROM_EMAIL] && strlen($params[self::FROM_EMAIL]) > 0)
? $params[self::FROM_EMAIL]
: $this->settingSolver->getSettingValue(
$siteDefault,
SiteSettingDefinition::SETTING_EMAIL_FROM
);

$emailFromName = (isset($params[self::FROM_NAME]) && $params[self::FROM_NAME] && strlen($params[self::FROM_NAME]) > 0)
? $params[self::FROM_NAME]
: $this->settingSolver->getSettingValue(
$siteDefault,
SiteSettingDefinition::SETTING_EMAIL_FROM_NAME
);

$message = new \Swift_Message($emailSubjectPrefix . $params[self::SUBJECT]);

if ($this->parameterBag->get('mailjet.dev.redirect.active') == 1) {
$message->addTo(
$this->parameterBag->get('mailjet.dev.redirect.email'),
isset($params[self::TO_NAME]) ?? null
);
} else {
$message->addTo(
$params[self::TO_EMAIL],
isset($params[self::TO_NAME]) ?? null
);
}

$contentData = [];
if (isset($params[self::CONTENT_DATA])) {
$contentData = $params[self::CONTENT_DATA];
}

$message->addFrom($emailFrom, $emailFromName)
->setBody(
$this->templating->render($params[self::CONTENT_TEMPLATE] . '-html.html.twig', $contentData),
'text/html'
)
->addPart($this->templating->render($params[self::CONTENT_TEMPLATE] . '-text.html.twig', $contentData));

if (isset($params[self::COPY_TO]) && strlen($params[self::COPY_TO])) {
$message->addCc($params[self::COPY_TO]);
}

if (isset($params[self::COPY_HIDDEN_TO]) && strlen($params[self::COPY_HIDDEN_TO])) {
$message->addBcc($params[self::COPY_HIDDEN_TO]);
}

if (isset($params[self::REPLY_TO]) && strlen($params[self::REPLY_TO])) {
$message->addReplyTo($params[self::REPLY_TO]);
}

if (isset($params[self::ATTACHMENT_DATA]) && isset($params[self::ATTACHMENT_FILENAME]) && isset($params[self::ATTACHMENT_CONTENT_TYPE])) {
$message->attach(
\Swift_Attachment::newInstance(
$params[self::ATTACHMENT_DATA],
$params[self::ATTACHMENT_FILENAME],
$params[self::ATTACHMENT_CONTENT_TYPE]
)
);
}

return $this->transport->send($message);
}
}

+ 101
- 0
Notification/SmsFactorNotification.php 查看文件

@@ -0,0 +1,101 @@
<?php

namespace Lc\SovBundle\Notification;

use Lc\SovBundle\Component\StringComponent;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Twig\Environment;

class SmsFactorNotification
{
const TO_USER = 'to-user';
const CONTENT_MESSAGE = 'content-message';
const CONTENT_TEMPLATE = 'content-template';
const CONTENT_DATA = 'content-data';

protected HttpClientInterface $client;
protected ParameterBagInterface $parameterBag;
protected MailMailjetNotification $mailMailjetNotification;
protected StringComponent $stringComponent;
protected Environment $templating;

public function __construct(
HttpClientInterface $client,
ParameterBagInterface $parameterBag,
MailMailjetNotification $mailMailjetNotification,
StringComponent $stringComponent,
Environment $templating
)
{
$this->client = $client;
$this->parameterBag = $parameterBag;
$this->mailMailjetNotification = $mailMailjetNotification;
$this->stringComponent = $stringComponent;
$this->templating = $templating;
}

public function send($params = [])
{
$user = isset($params[self::TO_USER]) ? $params[self::TO_USER] : null;

if ($user) {
$phone = $this->stringComponent->formatPhoneNumber($user->getPhone());

$message = '';
if (isset($params[self::CONTENT_MESSAGE])) {
$message = $params[self::CONTENT_MESSAGE];
} elseif (isset($params[self::CONTENT_TEMPLATE])) {
$template = $params[self::CONTENT_TEMPLATE];
$paramsTemplate = [];
if (isset($params[self::CONTENT_DATA]) && is_array($params[self::CONTENT_DATA])) {
$paramsTemplate = $params[self::CONTENT_DATA];
}
$message = $this->templating->render($template, $paramsTemplate);
}

if ($this->parameterBag->get('mailjet.dev.redirect.active') == 1) {
$this->mailMailjetNotification->send([
MailMailjetNotification::SUBJECT => 'Notification par SMS à ' . $phone,
MailMailjetNotification::TO_EMAIL => $user->getEmail(),
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/notification',
MailMailjetNotification::CONTENT_DATA => [
'message' => $message
],
]);

return true;
} else {
$token = $this->parameterBag->get('smsfactor.token');
$from = $this->parameterBag->get('smsfactor.from');

if ($token && strlen($token) > 0) {

$response = $this->client->request(
'GET',
'https://api.smsfactor.com/send',
[
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json; charset=utf-8',
'Accept' => 'application/json'
],
'query' => [
'sender' => $from,
'to' => $phone,
'text' => $message,
],
]
);

return $response;
} else {
throw new \ErrorException('Le token SMS SmsFactor n\'est pas défini.');
}
}
}

return false;
}

}

+ 32
- 9
Repository/AbstractRepositoryQuery.php 查看文件

@@ -48,13 +48,13 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
return $this;
}

public function count(): string
public function count()
{
return $this->query->getQuery()
->getSingleScalarResult();
}

public function findOne(): ?EntityInterface
public function findOne()
{
return $this->query->getQuery()
->setMaxResults(1)
@@ -82,6 +82,11 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
return $this->repository;
}

public function getQueryBuilder(): QueryBuilder
{
return $this->query;
}

protected function populateDqlId(&$data)
{
if (is_string($data)) {
@@ -105,16 +110,29 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface

public function groupBy(string $field): self
{
if (substr($field, 0, 1) === '.') {
return $this->groupBy($field) ;
if (strpos($field, '.')!==false) {
$this->addGroupBy($field) ;

} else {
return $this->groupBy('.'.$field) ;
$this->addGroupBy('.'.$field) ;
}
return $this;
}
/*
public function addGroupBy(string $field): self
{
if (strpos($field, '.')!==false) {
$this->query->addGroupBy($field) ;

} else {
$this->query->addGroupBy('.'.$field) ;
}
return $this;
}*/

public function orderBy(string $field, string $sort = 'ASC'): self
{
if (substr($field, 0, 1) === '.') {
if (strpos($field, '.')!==false) {
return $this->addOrderBy($field, $sort);
} else {
return $this->addOrderBy('.' . $field, $sort);
@@ -133,6 +151,11 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
return $this->andWhere('.'.$field.' = :'.$field)->setParameter($field, $value);
}

public function filterByOldUrl(string $oldUrl): self
{
return $this->andWhere('.oldUrls LIKE :oldUrl')->setParameter('oldUrl', '%'.$oldUrl.'%');
}

/*
* DEVALIAS
*/
@@ -158,15 +181,15 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
*/
public function filterIsParent():self
{
return $this->andWhere('.parent is NULL');
return $this->andWhere('.parent IS NULL');
}

public function filterIsChildren():self
{
return $this->andWhere('.parent is NOT NULL');
return $this->andWhere('.parent IS NOT NULL');
}

public function filterByParent(EntityInterface $parent):self
public function filterByParent(EntityInterface $parent = null):self
{
return $this->andWhere('.parent = :parent')->setParameter('parent', $parent);
}

+ 19
- 0
Repository/AbstractStore.php 查看文件

@@ -84,12 +84,29 @@ abstract class AbstractStore implements StoreInterface
return $query->findOne();
}

public function getOneByOldUrl(string $oldUrl, $query = null)
{
$query = $this->createDefaultQuery($query);
$query
->filterByOldUrl($oldUrl)
->filterIsOnline();

return $query->findOne();
}

public function get($query = null)
{
$query = $this->createDefaultQuery($query);
return $query->find();
}

public function getAll($query = null)
{
$query = $this->createQuery($query);
$query->filterIsOnlineAndOffline();
return $query->find();
}

public function getOnline($query = null)
{
$query = $this->createDefaultQuery($query);
@@ -100,9 +117,11 @@ abstract class AbstractStore implements StoreInterface
public function getParent(bool $isOnline = true, $query = null)
{
$query = $this->createDefaultQuery($query);

if ($isOnline) {
$query->filterIsOnline();
}

$query->filterIsParent();

return $query->find();

+ 206
- 0
Repository/EntityRepository.php 查看文件

@@ -0,0 +1,206 @@
<?php

namespace Lc\SovBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Orm\EntityRepositoryInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FilterDataDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\FormFactory;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\ComparisonType;
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository as EaEntityRepository;
use Knp\Component\Pager\PaginatorInterface;
use function Symfony\Component\Translation\t;

class EntityRepository
{

//protected EaEntityRepository $parent;
protected EntityManagerInterface $entityManager;
protected PaginatorInterface $paginator;

public function __construct(
//EaEntityRepository $entityRepository,
EntityManagerInterface $entityManager,
PaginatorInterface $paginator
) {
//$this->parent = $entityRepository;
$this->entityManager = $entityManager;
$this->paginator = $paginator;

}
public function createRepositoryQuery(RepositoryQueryInterface $repositoryQuery,SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters)
{
// if (!empty($searchDto->getQuery())) {
// $this->addSearchClause($repositoryQuery->getQuery(), $searchDto, $entityDto);
// }
//
// if (!empty($searchDto->getAppliedFilters())) {
// $this->addFilterClause($repositoryQuery->getQuery(), $searchDto, $entityDto, $filters, $fields);
// }

$this->addOrderClause($repositoryQuery, $searchDto, $entityDto);
return $repositoryQuery;
}

private function addSearchClause(QueryBuilder $queryBuilder, SearchDto $searchDto, EntityDto $entityDto): void
{
$query = $searchDto->getQuery();
$lowercaseQuery = mb_strtolower($query);
$isNumericQuery = is_numeric($query);
$isSmallIntegerQuery = ctype_digit($query) && $query >= -32768 && $query <= 32767;
$isIntegerQuery = ctype_digit($query) && $query >= -2147483648 && $query <= 2147483647;
$isUuidQuery = 1 === preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $query);

$dqlParameters = [
// adding '0' turns the string into a numeric value
'numeric_query' => is_numeric($query) ? 0 + $query : $query,
'uuid_query' => $query,
'text_query' => '%'.$lowercaseQuery.'%',
'words_query' => explode(' ', $lowercaseQuery),
];

$entitiesAlreadyJoined = [];
$configuredSearchableProperties = $searchDto->getSearchableProperties();
$searchableProperties = empty($configuredSearchableProperties) ? $entityDto->getAllPropertyNames() : $configuredSearchableProperties;
foreach ($searchableProperties as $propertyName) {
if ($entityDto->isAssociation($propertyName)) {
// support arbitrarily nested associations (e.g. foo.bar.baz.qux)
$associatedProperties = explode('.', $propertyName);
$numAssociatedProperties = \count($associatedProperties);

if (1 === $numAssociatedProperties) {
throw new \InvalidArgumentException(sprintf('The "%s" property included in the setSearchFields() method is not a valid search field. When using associated properties in search, you must also define the exact field used in the search (e.g. \'%s.id\', \'%s.name\', etc.)', $propertyName, $propertyName, $propertyName));
}

$originalPropertyName = $associatedProperties[0];
$originalPropertyMetadata = $entityDto->getPropertyMetadata($originalPropertyName);
$associatedEntityDto = $this->entityFactory->create($originalPropertyMetadata->get('targetEntity'));

for ($i = 0; $i < $numAssociatedProperties - 1; ++$i) {
$associatedEntityName = $associatedProperties[$i];
$associatedPropertyName = $associatedProperties[$i + 1];

if (!\in_array($associatedEntityName, $entitiesAlreadyJoined, true)) {
$parentEntityName = 0 === $i ? 'entity' : $associatedProperties[$i - 1];
$queryBuilder->leftJoin($parentEntityName.'.'.$associatedEntityName, $associatedEntityName);
$entitiesAlreadyJoined[] = $associatedEntityName;
}

if ($i < $numAssociatedProperties - 2) {
$propertyMetadata = $associatedEntityDto->getPropertyMetadata($associatedPropertyName);
$targetEntity = $propertyMetadata->get('targetEntity');
$associatedEntityDto = $this->entityFactory->create($targetEntity);
}
}

$entityName = $associatedEntityName;
$propertyName = $associatedPropertyName;
$propertyDataType = $associatedEntityDto->getPropertyDataType($propertyName);
} else {
$entityName = 'entity';
$propertyDataType = $entityDto->getPropertyDataType($propertyName);
}

$isSmallIntegerProperty = 'smallint' === $propertyDataType;
$isIntegerProperty = 'integer' === $propertyDataType;
$isNumericProperty = \in_array($propertyDataType, ['number', 'bigint', 'decimal', 'float']);
// 'citext' is a PostgreSQL extension (https://github.com/EasyCorp/EasyAdminBundle/issues/2556)
$isTextProperty = \in_array($propertyDataType, ['string', 'text', 'citext', 'array', 'simple_array']);
$isGuidProperty = \in_array($propertyDataType, ['guid', 'uuid']);

// this complex condition is needed to avoid issues on PostgreSQL databases
if (
($isSmallIntegerProperty && $isSmallIntegerQuery) ||
($isIntegerProperty && $isIntegerQuery) ||
($isNumericProperty && $isNumericQuery)
) {
$queryBuilder->orWhere(sprintf('%s.%s = :query_for_numbers', $entityName, $propertyName))
->setParameter('query_for_numbers', $dqlParameters['numeric_query']);
} elseif ($isGuidProperty && $isUuidQuery) {
$queryBuilder->orWhere(sprintf('%s.%s = :query_for_uuids', $entityName, $propertyName))
->setParameter('query_for_uuids', $dqlParameters['uuid_query']);
} elseif ($isTextProperty) {
$queryBuilder->orWhere(sprintf('LOWER(%s.%s) LIKE :query_for_text', $entityName, $propertyName))
->setParameter('query_for_text', $dqlParameters['text_query']);
$queryBuilder->orWhere(sprintf('LOWER(%s.%s) IN (:query_as_words)', $entityName, $propertyName))
->setParameter('query_as_words', $dqlParameters['words_query']);
}
}
}

private function addOrderClause(RepositoryQueryInterface $repositoryQuery, SearchDto $searchDto, EntityDto $entityDto): void
{
foreach ($searchDto->getSort() as $sortProperty => $sortOrder) {

$repositoryQuery->addOrderBy('.'.$sortProperty, $sortOrder);

// $aliases = $queryBuilder->getAllAliases();
// $sortFieldIsDoctrineAssociation = $entityDto->isAssociation($sortProperty);
//
// if ($sortFieldIsDoctrineAssociation) {
// $sortFieldParts = explode('.', $sortProperty, 2);
// // check if join has been added once before.
// if (!\in_array($sortFieldParts[0], $aliases)) {
// $queryBuilder->leftJoin('entity.'.$sortFieldParts[0], $sortFieldParts[0]);
// }
//
// if (1 === \count($sortFieldParts)) {
// $queryBuilder->addOrderBy('entity.'.$sortProperty, $sortOrder);
// } else {
// $queryBuilder->addOrderBy($sortProperty, $sortOrder);
// }
// } else {
// $queryBuilder->addOrderBy('entity.'.$sortProperty, $sortOrder);
// }
}
}

private function addFilterClause(QueryBuilder $queryBuilder, SearchDto $searchDto, EntityDto $entityDto, FilterCollection $configuredFilters, FieldCollection $fields): void
{
$filtersForm = $this->formFactory->createFiltersForm($configuredFilters, $this->adminContextProvider->getContext()->getRequest());
if (!$filtersForm->isSubmitted()) {
return;
}

$appliedFilters = $searchDto->getAppliedFilters();
$i = 0;
foreach ($filtersForm as $filterForm) {
$propertyName = $filterForm->getName();

$filter = $configuredFilters->get($propertyName);
// this filter is not defined or not applied
if (null === $filter || !isset($appliedFilters[$propertyName])) {
continue;
}

// if the form filter is not valid then we should not apply the filter
if (!$filterForm->isValid()) {
continue;
}

$submittedData = $filterForm->getData();
if (!\is_array($submittedData)) {
$submittedData = [
'comparison' => ComparisonType::EQ,
'value' => $submittedData,
];
}

$filterDataDto = FilterDataDto::new($i, $filter, current($queryBuilder->getRootAliases()), $submittedData);
$filter->apply($queryBuilder, $filterDataDto, $fields->getByProperty($propertyName), $entityDto);

++$i;
}
}



}

+ 1
- 1
Repository/File/FileRepositoryQuery.php 查看文件

@@ -9,6 +9,6 @@ class FileRepositoryQuery extends AbstractRepositoryQuery implements FileReposit
{
public function __construct(FileRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'file', $paginator);
}
}

+ 1
- 1
Repository/Newsletter/NewsletterRepositoryQuery.php 查看文件

@@ -9,6 +9,6 @@ class NewsletterRepositoryQuery extends AbstractRepositoryQuery implements Newsl
{
public function __construct(NewsletterRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'newsletter', $paginator);
}
}

+ 3
- 3
Repository/Reminder/ReminderRepositoryQuery.php 查看文件

@@ -12,7 +12,7 @@ class ReminderRepositoryQuery extends AbstractRepositoryQuery implements Reminde

public function __construct(ReminderRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'reminder', $paginator);
}

public function filterByDone($done = false): self
@@ -28,7 +28,7 @@ class ReminderRepositoryQuery extends AbstractRepositoryQuery implements Reminde
$this->isJoinUser = true;

return $this
->leftJoin('.users', 'u');
->leftJoin('.users', 'users');
}
return $this;
}
@@ -37,7 +37,7 @@ class ReminderRepositoryQuery extends AbstractRepositoryQuery implements Reminde
{
$this->joinUser();
return $this
->having('COUNT(u.id) = 0')
->having('COUNT(users.id) = 0')
->orHaving(':user MEMBER OF .users')
->setParameter(':user', $user);
}

+ 3
- 5
Repository/RepositoryQueryInterface.php 查看文件

@@ -11,9 +11,9 @@ interface RepositoryQueryInterface

public function call(callable $fn):self;

public function count(): string;
public function count();

public function findOne(): ?EntityInterface;
public function findOne();

public function find(): array;

@@ -23,8 +23,6 @@ interface RepositoryQueryInterface

public function getRepository(): ServiceEntityRepository;

public function groupBy(string $field):self;

public function orderBy(string $field, string $sort = 'ASC'):self;

public function filterById(int $id):self;
@@ -46,4 +44,4 @@ interface RepositoryQueryInterface
public function filterIsDeleted():self;

public function filterIsOnlineAndOffline():self;
}
}

+ 1
- 1
Repository/Setting/SiteSettingRepositoryQuery.php 查看文件

@@ -9,6 +9,6 @@ class SiteSettingRepositoryQuery extends AbstractRepositoryQuery implements Site
{
public function __construct(SiteSettingRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'siteSetting', $paginator);
}
}

+ 1
- 1
Repository/Site/NewsRepositoryQuery.php 查看文件

@@ -10,6 +10,6 @@ class NewsRepositoryQuery extends AbstractRepositoryQuery implements NewsReposit

public function __construct(NewsRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'news', $paginator);
}
}

+ 1
- 1
Repository/Site/PageRepositoryQuery.php 查看文件

@@ -9,7 +9,7 @@ class PageRepositoryQuery extends AbstractRepositoryQuery implements PageReposit
{
public function __construct(PageRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'page', $paginator);
}

}

+ 1
- 1
Repository/Site/SiteRepositoryQuery.php 查看文件

@@ -9,6 +9,6 @@ class SiteRepositoryQuery extends AbstractRepositoryQuery implements SiteReposit
{
public function __construct(SiteRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'r', $paginator);
parent::__construct($repository, 'site', $paginator);
}
}

+ 5
- 0
Repository/Site/SiteStore.php 查看文件

@@ -29,4 +29,9 @@ class SiteStore extends AbstractStore implements SiteStoreInterface
{
return $query;
}

public function getOneDefault()
{
return $this->getOneByDevAlias('default');
}
}

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存