@@ -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); | |||
} | |||
} | |||
} |
@@ -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.'); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 = [ |
@@ -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; |
@@ -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; |
@@ -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 | |||
{ |
@@ -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 ''; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SfAbstractController; | |||
abstract class AbstractController extends SfAbstractController | |||
{ | |||
use ControllerTrait; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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'); | |||
} |
@@ -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( |
@@ -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')); |
@@ -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.' | |||
); | |||
} | |||
} |
@@ -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 | |||
); | |||
} | |||
} | |||
} |
@@ -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); |
@@ -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); |
@@ -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; | |||
} | |||
@@ -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( |
@@ -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(); | |||
} | |||
} |
@@ -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()) | |||
]; | |||
} | |||
@@ -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'; | |||
} |
@@ -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) | |||
); | |||
} | |||
} |
@@ -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'), | |||
]; | |||
} | |||
} |
@@ -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), | |||
]; | |||
} | |||
} |
@@ -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(), | |||
]; | |||
} | |||
} |
@@ -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) | |||
]; | |||
} | |||
} |
@@ -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()), | |||
]; | |||
} | |||
} |
@@ -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, | |||
]; | |||
} | |||
@@ -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; | |||
/** |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -31,4 +31,10 @@ trait SortableTrait | |||
$this->position = $position; | |||
return $this; | |||
} | |||
public function clearPosition(): self | |||
{ | |||
$this->position = null; | |||
return $this; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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'; | |||
} |
@@ -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(), | |||
])); | |||
} | |||
} |
@@ -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'); | |||
} | |||
} |
@@ -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 | |||
} | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
<?php | |||
namespace Lc\SovBundle\EventSubscriber\Ticket; | |||
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Event\Ticket\TicketEvent; | |||
use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; | |||
use Lc\SovBundle\Notification\MailMailjetNotification; | |||
use Lc\SovBundle\Repository\User\UserStore; | |||
use Lc\SovBundle\Solver\Ticket\TicketSolver; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; | |||
class SendNotificationTicketEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected MailMailjetNotification $mailMailjetNotification; | |||
protected UserStore $userStore; | |||
protected AuthorizationCheckerInterface $authorizationChecker; | |||
protected TicketSolver $ticketSolver; | |||
public function __construct( | |||
MailMailjetNotification $mailMailjetNotification, | |||
UserStore $userStore, | |||
AuthorizationCheckerInterface $authorizationChecker, | |||
TicketSolver $ticketSolver | |||
) { | |||
$this->mailMailjetNotification = $mailMailjetNotification; | |||
$this->userStore = $userStore; | |||
$this->authorizationChecker = $authorizationChecker; | |||
$this->ticketSolver = $ticketSolver; | |||
} | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
TicketEvent::NEW_MESSAGE_EVENT => ['sendNotificationAfterNewMessage'], | |||
TicketEvent::NEW_TICKET_EVENT => ['sendNotificationAfterNewTicket'], | |||
]; | |||
} | |||
public function sendNotificationAfterNewTicket(TicketEvent $ticketEvent) | |||
{ | |||
$ticket = $ticketEvent->getTicket(); | |||
$lastMessage = $this->ticketSolver->getLastMessage($ticket); | |||
if ($ticket->getUser()) { | |||
$firstname = $ticket->getUser()->getFirstname(); | |||
$email = $ticket->getUser()->getEmail(); | |||
} else { | |||
$firstname = $ticket->getVisitorFirstname(); | |||
$email = $ticket->getVisitorEmail(); | |||
} | |||
if ($lastMessage->getAnswerByAdmin()) { | |||
// envoi email au client | |||
$this->mailMailjetNotification->send( | |||
[ | |||
MailMailjetNotification::SUBJECT => 'Vous avez reçu un nouveau message', | |||
MailMailjetNotification::TO_EMAIL => $email, | |||
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new-by-admin', | |||
MailMailjetNotification::CONTENT_DATA => [ | |||
'firstname' => $firstname, | |||
'ticket' => $ticket, | |||
], | |||
] | |||
); | |||
} else { | |||
$this->mailMailjetNotification->send( | |||
[ | |||
MailMailjetNotification::SUBJECT => 'Nouvelle demande', | |||
MailMailjetNotification::TO_EMAIL => $email, | |||
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-new', | |||
MailMailjetNotification::CONTENT_DATA => [ | |||
'firstname' => $firstname, | |||
'ticket' => $ticket, | |||
], | |||
] | |||
); | |||
} | |||
$this->notifyUser($ticket); | |||
} | |||
public function sendNotificationAfterNewMessage(TicketEvent $ticketEvent) | |||
{ | |||
$ticket = $ticketEvent->getTicket(); | |||
$lastMessage = $this->ticketSolver->getLastMessage($ticket); | |||
if ($ticket->getUser()) { | |||
$firstname = $ticket->getUser()->getFirstname(); | |||
$email = $ticket->getUser()->getEmail(); | |||
} else { | |||
$firstname = $ticket->getVisitorFirstname(); | |||
$email = $ticket->getVisitorEmail(); | |||
} | |||
if ($lastMessage->getAnswerByAdmin()) { | |||
// envoi email au client | |||
$this->mailMailjetNotification->send( | |||
[ | |||
MailMailjetNotification::SUBJECT => 'Réponse à votre demande', | |||
MailMailjetNotification::TO_EMAIL => $email, | |||
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-response', | |||
MailMailjetNotification::CONTENT_DATA => [ | |||
'firstname' => $firstname, | |||
'ticket' => $ticket, | |||
], | |||
] | |||
); | |||
} | |||
$this->notifyUser($ticket); | |||
} | |||
protected function notifyUser(TicketInterface $ticket): void | |||
{ | |||
// notifyAdmin | |||
$usersToNotify = $this->userStore->getByTicketTypesNotification($ticket->getType()); | |||
foreach ($usersToNotify as $userToNotify) { | |||
if ($this->authorizationChecker->isGranted('ROLE_ADMIN', $userToNotify)) { | |||
$this->mailMailjetNotification->send( | |||
[ | |||
MailMailjetNotification::SUBJECT => 'Nouveau ticket sur Place du Local', | |||
MailMailjetNotification::TO_EMAIL => $userToNotify->getEmail(), | |||
MailMailjetNotification::CONTENT_TEMPLATE => 'mail/ticket-notification', | |||
MailMailjetNotification::CONTENT_DATA => [ | |||
'firstname' => $userToNotify->getFirstname(), | |||
'ticket' => $ticket, | |||
'ticketMessage' => $ticket->getTicketMessages()[0], | |||
], | |||
] | |||
); | |||
} | |||
} | |||
} | |||
} |
@@ -12,6 +12,8 @@ class NewsFactory extends AbstractFactory implements NewsFactoryInterface | |||
{ | |||
$news = new News(); | |||
$news->setStatus(1); | |||
return $news; | |||
} | |||
@@ -12,6 +12,8 @@ class PageFactory extends AbstractFactory implements PageFactoryInterface | |||
{ | |||
$page = new Page(); | |||
$page->setStatus(1); | |||
return $page; | |||
} | |||
} |
@@ -12,6 +12,8 @@ class GroupUserFactory extends AbstractFactory implements GroupUserFactoryInterf | |||
{ | |||
$groupUser = new GroupUser(); | |||
$groupUser->setStatus(1); | |||
return $groupUser; | |||
} | |||
} |
@@ -19,7 +19,7 @@ final class BooleanField implements FieldInterface | |||
return (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setTemplatePath('@LcSov/adminlte/crud/field/boolean.html.twig') | |||
->setTemplatePath('@LcSov/adminlte/crud/field/toggle.html.twig') | |||
->setFormType(CheckboxType::class); | |||
} | |||
@@ -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 { | |||
// } | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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' | |||
); | |||
} | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
@@ -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 . '%'); | |||
} | |||
} | |||
@@ -0,0 +1,38 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter\Ticket; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Field\Filter\AssociationFilter; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class TicketEmailFilter extends AssociationFilter | |||
{ | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
TextType::class, | |||
array( | |||
'required' => false, | |||
'attr' => array( | |||
'class' => ' input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$repositoryQuery->filterByEmail('%'.$filteredValue.'%'); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter\Ticket; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Field\Filter\AssociationFilter; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class TicketFirstnameFilter extends AssociationFilter | |||
{ | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
TextType::class, | |||
array( | |||
'required' => false, | |||
'attr' => array( | |||
'class' => ' input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$repositoryQuery->filterByFirstname('%'.$filteredValue.'%'); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter\Ticket; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Field\Filter\AssociationFilter; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class TicketLastnameFilter extends AssociationFilter | |||
{ | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
TextType::class, | |||
array( | |||
'required' => false, | |||
'attr' => array( | |||
'class' => ' input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$repositoryQuery->filterByLastname('%'.$filteredValue.'%'); | |||
} | |||
} | |||
} |
@@ -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,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) { |
@@ -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() |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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( | |||
[ | |||
] | |||
); | |||
} | |||
} |
@@ -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') { |
@@ -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), | |||
] | |||
); | |||
} | |||
} | |||
} |
@@ -6,12 +6,13 @@ use Lc\SovBundle\Doctrine\EntityManager; | |||
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\AbstractType; | |||
use Symfony\Component\Form\Extension\Core\Type\HiddenType; | |||
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextareaType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
class TicketMessageFormType extends AbstractType | |||
class TicketMessageAdminFormType extends AbstractType | |||
{ | |||
protected $em; | |||
protected $translatorAdmin; | |||
@@ -31,13 +32,12 @@ class TicketMessageFormType extends AbstractType | |||
'required' => true | |||
] | |||
); | |||
$builder->add( | |||
'submit', | |||
SubmitType::class, | |||
[ | |||
'label' => $this->translatorAdmin->transAction('send') | |||
] | |||
'answerByAdmin', | |||
HiddenType::class, | |||
[ | |||
'data' => 1 | |||
] | |||
); | |||
} | |||
@@ -2,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), | |||
]); | |||
} | |||
} |
@@ -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, |
@@ -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', | |||
] | |||
); | |||
} |
@@ -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', | |||
] | |||
); | |||
} | |||
} |
@@ -39,7 +39,7 @@ abstract class FileModel implements SortableInterface, BlameableInterface, Times | |||
public function __toString(){ | |||
return $this->getLegend(); | |||
return ''.$this->getLegend(); | |||
} | |||
public function getPath(): ?string |
@@ -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; | |||
@@ -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; | |||
@@ -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 |
@@ -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; |
@@ -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") | |||
*/ |
@@ -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; | |||
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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(); |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -29,4 +29,9 @@ class SiteStore extends AbstractStore implements SiteStoreInterface | |||
{ | |||
return $query; | |||
} | |||
public function getOneDefault() | |||
{ | |||
return $this->getOneByDevAlias('default'); | |||
} | |||
} |