Charly 10ヶ月前
コミット
31ed564668
100個のファイルの変更2668行の追加259行の削除
  1. +22
    -7
      Authenticator/LoginFormAuthenticator.php
  2. +33
    -1
      Builder/User/UserBuilder.php
  3. +20
    -0
      Component/ArrayComponent.php
  4. +12
    -7
      Component/CitiesComponent.php
  5. +5
    -0
      Component/DateComponent.php
  6. +6
    -3
      Component/EntityComponent.php
  7. +15
    -1
      Component/FileComponent.php
  8. +46
    -14
      Component/MetaComponent.php
  9. +10
    -1
      Container/ComponentContainer.php
  10. +8
    -0
      Container/File/FileContainer.php
  11. +7
    -0
      Container/Newsletter/NewsletterContainer.php
  12. +6
    -0
      Container/Reminder/ReminderContainer.php
  13. +7
    -0
      Container/Setting/SiteSettingContainer.php
  14. +6
    -0
      Container/Site/NewsContainer.php
  15. +6
    -0
      Container/Site/PageContainer.php
  16. +5
    -0
      Container/Site/SiteContainer.php
  17. +7
    -0
      Container/Ticket/TicketContainer.php
  18. +5
    -0
      Container/Ticket/TicketMessageContainer.php
  19. +5
    -0
      Container/User/GroupUserContainer.php
  20. +5
    -0
      Container/User/UserContainer.php
  21. +99
    -50
      Controller/AbstractAdminController.php
  22. +81
    -48
      Controller/ControllerTrait.php
  23. +50
    -0
      Controller/Dashboard/CommandAdminController.php
  24. +3
    -2
      Controller/Dashboard/DashboardAdminController.php
  25. +43
    -5
      Controller/ErrorController.php
  26. +4
    -4
      Controller/Security/SecurityAdminController.php
  27. +120
    -0
      Controller/User/UserAdminController.php
  28. +88
    -0
      Definition/ApplicationDefinition.php
  29. +16
    -7
      Definition/Field/AbstractFieldDefinition.php
  30. +2
    -2
      Definition/Field/Site/PageFieldDefinition.php
  31. +13
    -13
      Definition/SiteSettingDefinition.php
  32. +1
    -1
      Definition/SiteSettingDefinitionInterface.php
  33. +21
    -16
      DependencyInjection/LcSovExtension.php
  34. +9
    -1
      Doctrine/Extension/BlameableInterface.php
  35. +2
    -2
      Doctrine/Extension/BlameableTrait.php
  36. +2
    -0
      Doctrine/Extension/DevAliasInterface.php
  37. +26
    -0
      Doctrine/Extension/ImageTrait.php
  38. +10
    -0
      Doctrine/Extension/OpenGraphInterface.php
  39. +2
    -2
      Doctrine/Extension/OpenGraphTrait.php
  40. +8
    -0
      Doctrine/Extension/SeoInterface.php
  41. +3
    -0
      Doctrine/Extension/SluggableInterface.php
  42. +5
    -0
      Doctrine/Extension/SortableInterface.php
  43. +4
    -0
      Doctrine/Extension/StatusInterface.php
  44. +6
    -0
      Doctrine/Extension/TimestampableInterface.php
  45. +5
    -1
      Doctrine/Extension/TranslatableInterface.php
  46. +4
    -1
      Doctrine/Pattern/AbstractFullEntity.php
  47. +5
    -3
      EventListener/ExceptionListener.php
  48. +3
    -2
      Factory/File/FileFactory.php
  49. +3
    -2
      Factory/Newsletter/NewsletterFactory.php
  50. +3
    -3
      Factory/Reminder/ReminderFactory.php
  51. +7
    -1
      Factory/Reminder/ReminderFactoryInterface.php
  52. +3
    -2
      Factory/Setting/SiteSettingFactory.php
  53. +11
    -1
      Factory/Setting/SiteSettingFactoryInterface.php
  54. +3
    -3
      Factory/Site/NewsFactory.php
  55. +3
    -1
      Factory/Site/NewsFactoryInterface.php
  56. +3
    -2
      Factory/Site/PageFactory.php
  57. +3
    -1
      Factory/Site/PageFactoryInterface.php
  58. +3
    -2
      Factory/Site/SiteFactory.php
  59. +3
    -1
      Factory/Site/SiteFactoryInterface.php
  60. +3
    -2
      Factory/Ticket/TicketFactory.php
  61. +3
    -1
      Factory/Ticket/TicketFactoryInterface.php
  62. +3
    -2
      Factory/Ticket/TicketMessageFactory.php
  63. +4
    -1
      Factory/Ticket/TicketMessageFactoryInterface.php
  64. +3
    -2
      Factory/User/GroupUserFactory.php
  65. +3
    -1
      Factory/User/GroupUserFactoryInterface.php
  66. +4
    -2
      Factory/User/UserFactory.php
  67. +3
    -1
      Factory/User/UserFactoryInterface.php
  68. +149
    -0
      Field/AssociationField.php
  69. +70
    -0
      Form/Common/CookieConsentTypeExtension.php
  70. +0
    -1
      Form/Common/FileManagerType.php
  71. +258
    -0
      Form/Common/FileUploadType.php
  72. +15
    -3
      Form/Setting/BaseSettingType.php
  73. +65
    -0
      Form/User/ConfirmDeleteUserFormType.php
  74. +32
    -0
      Generator/PdfGenerator.php
  75. +4
    -4
      LcSovBundle.php
  76. +48
    -2
      Model/File/FileInterface.php
  77. +77
    -1
      Model/Newsletter/NewsletterInterface.php
  78. +61
    -1
      Model/Reminder/ReminderInterface.php
  79. +17
    -0
      Model/Setting/SettingInterface.php
  80. +22
    -0
      Model/Setting/SiteSettingInterface.php
  81. +93
    -2
      Model/Site/NewsInterface.php
  82. +1
    -3
      Model/Site/NewsModel.php
  83. +64
    -1
      Model/Site/PageInterface.php
  84. +15
    -2
      Model/Site/SiteInterface.php
  85. +68
    -1
      Model/Ticket/TicketInterface.php
  86. +42
    -1
      Model/Ticket/TicketMessageInterface.php
  87. +2
    -1
      Model/Ticket/TicketModel.php
  88. +72
    -1
      Model/User/GroupUserInterface.php
  89. +101
    -1
      Model/User/UserInterface.php
  90. +18
    -2
      Model/User/UserModel.php
  91. +142
    -1
      Repository/AbstractRepositoryInterface.php
  92. +44
    -1
      Repository/AbstractRepositoryQuery.php
  93. +7
    -0
      Repository/AbstractStore.php
  94. +50
    -0
      Repository/File/FileRepositoryQueryInterface.php
  95. +1
    -2
      Repository/File/FileStore.php
  96. +30
    -0
      Repository/File/FileStoreInterface.php
  97. +51
    -0
      Repository/Newsletter/NewsletterRepositoryQueryInterface.php
  98. +1
    -2
      Repository/Newsletter/NewsletterStore.php
  99. +30
    -0
      Repository/Newsletter/NewsletterStoreInterface.php
  100. +76
    -1
      Repository/Reminder/ReminderRepositoryQueryInterface.php

+ 22
- 7
Authenticator/LoginFormAuthenticator.php ファイルの表示

@@ -2,6 +2,9 @@

namespace Lc\SovBundle\Authenticator;

use Lc\SovBundle\Builder\User\UserBuilder;
use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\User\UserStore;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormFactoryInterface;
@@ -13,6 +16,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
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;
@@ -27,17 +31,19 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator

protected UrlGeneratorInterface $urlGenerator;
protected UserStore $userStore;
protected UserBuilder $userBuilder;
protected FormFactoryInterface $formFactory;
protected ParameterBagInterface $parameterBag;

public function __construct(
UrlGeneratorInterface $urlGenerator,
UserStore $userStore,
UserContainer $userContainer,
FormFactoryInterface $formFactory,
ParameterBagInterface $parameterBag
) {
$this->urlGenerator = $urlGenerator;
$this->userStore = $userStore;
$this->userStore = $userContainer->getStore();
$this->userBuilder = $userContainer->getBuilder();
$this->formFactory = $formFactory;
$this->parameterBag = $parameterBag;
}
@@ -49,7 +55,8 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator

public function authenticate(Request $request): PassportInterface
{
$email = $request->request->get('email');

$email = trim($request->request->get('email'));
$password = $request->request->get('password');
$csrfToken = $request->request->get('_csrf_token');

@@ -58,7 +65,10 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
return $this->userStore->getOneByEmail($userIdentifier);
}),
new PasswordCredentials($password),
[new CsrfTokenBadge('authenticate', $csrfToken)]
[
new CsrfTokenBadge('authenticate', $csrfToken),
new RememberMeBadge()
]
);
}

@@ -67,17 +77,21 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
TokenInterface $token,
string $providerKey
): RedirectResponse {



$routeName = 'home';
$email = $request->request->get('email');
$email = trim($request->request->get('email'));
$loginRedirection = $this->parameterBag->get('lc_sov.login_redirection');
$useReferer = $loginRedirection['redirect_referer'];
$rolesRedirection = $loginRedirection['roles_redirection'];


$user = $this->userStore->getOneByEmail($email);

if (isset($useReferer) && $useReferer == true) {
$url = $request->request->get('_target_path');
} else {
$user = $this->userStore->getOneByEmail($email);

if (!empty($user)) {
$roles = $user->getRoles();

@@ -88,6 +102,7 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
}
}
}
$this->userBuilder->setLastLogin($user);

if (isset($url) && !empty($url)) {
return new RedirectResponse($url);

+ 33
- 1
Builder/User/UserBuilder.php ファイルの表示

@@ -3,10 +3,14 @@
namespace Lc\SovBundle\Builder\User;

use Doctrine\ORM\EntityManagerInterface;
use Lc\CaracoleBundle\Model\Address\AddressInterface;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Factory\User\UserFactory;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Repository\User\UserStore;
use Lc\SovBundle\Solver\User\UserSolver;

@@ -15,11 +19,29 @@ class UserBuilder
protected EntityManagerInterface $entityManager;
protected UserStore $userStore;
protected UserSolver $userSolver;
public function __construct(EntityManagerInterface $entityManager, UserStore $userStore, UserSolver $userSolver)
protected UserFactory $userFactory;

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


public function create(string $email, string $password, array $roles = [])
{
$user = $this->userFactory->create();
$user->setEmail($email);
$user->setPassword($password);

$user->setRoles($roles);
$this->entityManager->create($user);
$this->entityManager->flush();

return $user;

}

public function setNewsletter(UserInterface $user, NewsletterInterface $newsletter, bool $subscribeNewsletter): void
@@ -41,6 +63,7 @@ class UserBuilder

return $entity;
}

public function initBlameableUpdatedSystem(EntityInterface $entity)
{
$userSystem = $this->userStore->getOneByDevAlias('system');
@@ -63,4 +86,13 @@ class UserBuilder
$entity->setUpdatedBy($user);
}
}

public function setLastLogin(?UserInterface $user)
{
if ($user instanceof UserInterface) {
$user->setLastLogin(new \DateTime());
$this->entityManager->update($user);
$this->entityManager->flush();
}
}
}

+ 20
- 0
Component/ArrayComponent.php ファイルの表示

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

namespace Lc\SovBundle\Component;

use Cocur\Slugify\Slugify;

class ArrayComponent
{
public function contains(array $array, $entity): bool
{
foreach($array as $entityTest) {
if(get_class($entityTest) == get_class($entity)
&& $entityTest->getId() == $entity->getId()) {
return true;
}
}

return false;
}
}

+ 12
- 7
Component/CitiesComponent.php ファイルの表示

@@ -85,15 +85,20 @@ class CitiesComponent

public function callAddressApi($query)
{
$provider = $this->getGeocoderProvider() ;;
$query = GeocodeQuery::create($query)->withData('type', 'housenumber');
$results = $provider->geocodeQuery($query);
$resultsToReturn = array();
foreach($results as $result) {
if ($result->getStreetNumber() && strlen($result->getStreetNumber()) > 0) {
$resultsToReturn[] = $result;
$resultsToReturn = [];

if(!is_null($query)) {
$provider = $this->getGeocoderProvider() ;
$query = GeocodeQuery::create($query)->withData('type', 'housenumber');
$results = $provider->geocodeQuery($query);

foreach($results as $result) {
if ($result->getStreetNumber() && strlen($result->getStreetNumber()) > 0) {
$resultsToReturn[] = $result;
}
}
}

return $resultsToReturn;
}


+ 5
- 0
Component/DateComponent.php ファイルの表示

@@ -70,4 +70,9 @@ class DateComponent
return $hour ;
}

public function getTotalMinutes(\DateTimeInterface $time): int
{
return (int) $time->format('H') * 60 + (int) $time->format('i');
}

}

+ 6
- 3
Component/EntityComponent.php ファイルの表示

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

use Doctrine\ORM\EntityManagerInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\SeoInterface;
@@ -31,8 +32,8 @@ class EntityComponent

public function duplicateEntity($entity)
{

$newEntity = clone $entity;

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

//Dupplication de l'image ou du fichier lier
@@ -68,9 +69,11 @@ class EntityComponent
$newEntity->setCreatedAt(new \DateTime());
}

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

//Ne pas utiliser create ici! Sinon pour certaine entité comme ProductFamily on réajoute un orginProduct
$this->entityManager->create($newEntity, false);

return $newEntity;
}

@@ -109,4 +112,4 @@ class EntityComponent
}
return $entity;
}
}
}

+ 15
- 1
Component/FileComponent.php ファイルの表示

@@ -5,16 +5,27 @@ namespace Lc\SovBundle\Component;

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

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

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

public function getAssetUrl($path)
{
$context = $this->router->getContext();
$host = $context->getScheme().'://'.$context->getHost().'/';

return $host.$path;
}

/**
@@ -34,6 +45,9 @@ class FileComponent
$path = substr($path, 1);
}

// gestion des accents et des espaces
$path = urldecode($path);

if ($path) {

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

+ 46
- 14
Component/MetaComponent.php ファイルの表示

@@ -4,14 +4,25 @@ namespace Lc\SovBundle\Component;

class MetaComponent
{
protected FileComponent $fileComponent;
protected StringComponent $stringComponent;

public function getMetaTitle($entity)
public function __construct(FileComponent $fileComponent, StringComponent $stringComponent)
{
$this->fileComponent = $fileComponent;
$this->stringComponent = $stringComponent;
}

public function getMetaTitle($entity, $title = null)
{
if($entity) {
if(method_exists($entity, 'getMetaTitle')) {
if(method_exists($entity, 'getMetaTitle') && $entity->getMetaTitle()) {
return $entity->getMetaTitle() ;
}
elseif(method_exists($entity, 'getTitle')) {
elseif(!is_null($title)) {
return $title;
}
elseif(method_exists($entity, 'getTitle') && $entity->getTitle()) {
return $entity->getTitle() ;
}
}
@@ -22,24 +33,27 @@ class MetaComponent
public function getMetaDescription($entity)
{
if($entity) {
if(method_exists($entity, 'getMetaDescription')) {
if(method_exists($entity, 'getMetaDescription') && $entity->getMetaDescription()) {
return $entity->getMetaDescription() ;
}
elseif(method_exists($entity, 'getDescription')) {
return $entity->getDescription() ;
elseif(method_exists($entity, 'getDescription') && $entity->getDescription()) {
return $this->formatDescription($entity->getDescription());
}
}

return '' ;
}

public function getOpenGraphTitle($entity)
public function getOpenGraphTitle($entity, $title = null)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphTitle')) {
if(method_exists($entity, 'getOpenGraphTitle') && $entity->getOpenGraphTitle()) {
return $entity->getOpenGraphTitle() ;
}
elseif(method_exists($entity, 'getTitle')) {
elseif(!is_null($title)) {
return $title;
}
elseif(method_exists($entity, 'getTitle') && $entity->getTitle()) {
return $entity->getTitle() ;
}
}
@@ -50,11 +64,11 @@ class MetaComponent
public function getOpenGraphDescription($entity)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphDescription')) {
if(method_exists($entity, 'getOpenGraphDescription') && $entity->getOpenGraphDescription()) {
return $entity->getOpenGraphDescription() ;
}
elseif(method_exists($entity, 'getDescription')) {
return $entity->getDescription() ;
elseif(method_exists($entity, 'getDescription') && $entity->getDescription()) {
return $this->formatDescription($entity->getDescription());
}
}

@@ -64,10 +78,10 @@ class MetaComponent
public function getOpenGraphImage($entity)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphImage')) {
if(method_exists($entity, 'getOpenGraphImage') && $entity->getOpenGraphImage()) {
return $entity->getOpenGraphImage() ;
}
elseif(method_exists($entity, 'getImage')) {
elseif(method_exists($entity, 'getImage') && $entity->getImage()) {
return $entity->getImage() ;
}
}
@@ -75,4 +89,22 @@ class MetaComponent
return '' ;
}

public function getOpenGraphImageUrl($entity)
{
$image = $this->getOpenGraphImage($entity);
if($image && $image->getPath() && strlen($image->getPath()) > 0) {
return $this->fileComponent->getAssetUrl($image->getPath());
}

return '';
}

public function formatDescription($description)
{
$description = trim($description);
$description = $this->stringComponent->limitText($description, 50);
$description = str_replace("\r\n","",$description);

return $description;
}
}

+ 10
- 1
Container/ComponentContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container;

use Lc\SovBundle\Component\ArrayComponent;
use Lc\SovBundle\Component\CitiesComponent;
use Lc\SovBundle\Component\CookieComponent;
use Lc\SovBundle\Component\DateComponent;
@@ -25,6 +26,7 @@ class ComponentContainer
protected NumberComponent $numberComponent;
protected PointLocationComponent $pointLocationComponent;
protected StringComponent $stringComponent;
protected ArrayComponent $arrayComponent;

public function __construct(
CitiesComponent $citiesComponent,
@@ -36,7 +38,8 @@ class ComponentContainer
MetaComponent $metaComponent,
NumberComponent $numberComponent,
PointLocationComponent $pointLocationComponent,
StringComponent $stringComponent
StringComponent $stringComponent,
ArrayComponent $arrayComponent
) {
$this->citiesComponent = $citiesComponent;
$this->cookieComponent = $cookieComponent;
@@ -48,6 +51,7 @@ class ComponentContainer
$this->numberComponent = $numberComponent;
$this->pointLocationComponent = $pointLocationComponent;
$this->stringComponent = $stringComponent;
$this->arrayComponent = $arrayComponent;
}

public function getCitiesComponent(): CitiesComponent
@@ -99,4 +103,9 @@ class ComponentContainer
{
return $this->stringComponent;
}

public function getArrayComponent(): ArrayComponent
{
return $this->arrayComponent;
}
}

+ 8
- 0
Container/File/FileContainer.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Container\File;

use App\Entity\File\File;
use Lc\SovBundle\Factory\File\FileFactory;
use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Repository\File\FileRepositoryQuery;
use Lc\SovBundle\Repository\File\FileStore;

@@ -22,6 +24,11 @@ class FileContainer
$this->store = $store;
}

public static function getEntityFqcn()
{
return File::class;
}

public function getFactory(): FileFactory
{
return $this->factory;
@@ -36,4 +43,5 @@ class FileContainer
{
return $this->store;
}

}

+ 7
- 0
Container/Newsletter/NewsletterContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Newsletter;

use App\Entity\Newsletter\Newsletter;
use Lc\SovBundle\Definition\Field\Newsletter\NewsletterFieldDefinition;
use Lc\SovBundle\Factory\Newsletter\NewsletterFactory;
use Lc\SovBundle\Repository\Newsletter\NewsletterRepositoryQuery;
@@ -26,6 +27,12 @@ class NewsletterContainer
$this->fieldDefinition = $fieldDefinition;
}

public static function getEntityFqcn()
{
return Newsletter::class;
}


public function getFactory(): NewsletterFactory
{
return $this->factory;

+ 6
- 0
Container/Reminder/ReminderContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Reminder;

use App\Entity\Reminder\Reminder;
use Lc\SovBundle\Factory\Reminder\ReminderFactory;
use Lc\SovBundle\Repository\Reminder\ReminderRepositoryQuery;
use Lc\SovBundle\Repository\Reminder\ReminderStore;
@@ -22,6 +23,11 @@ class ReminderContainer
$this->store = $store;
}

public static function getEntityFqcn()
{
return Reminder::class;
}

public function getFactory(): ReminderFactory
{
return $this->factory;

+ 7
- 0
Container/Setting/SiteSettingContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Setting;

use App\Entity\Setting\SiteSetting;
use Lc\SovBundle\Definition\SiteSettingDefinition;
use Lc\SovBundle\Factory\Setting\SiteSettingFactory;
use Lc\SovBundle\Repository\Setting\SiteSettingRepositoryQuery;
@@ -30,6 +31,12 @@ class SiteSettingContainer
$this->settingSolver = $settingSolver;
}


public static function getEntityFqcn()
{
return SiteSetting::class;
}

public function getFactory(): SiteSettingFactory
{
return $this->factory;

+ 6
- 0
Container/Site/NewsContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Site;

use App\Entity\Site\News;
use Lc\SovBundle\Definition\Field\Site\NewsFieldDefinition;
use Lc\SovBundle\Factory\Site\NewsFactory;
use Lc\SovBundle\Repository\Site\NewsRepositoryQuery;
@@ -26,6 +27,11 @@ class NewsContainer
$this->fieldDefinition = $fieldDefinition;
}


public static function getEntityFqcn()
{
return News::class;
}
public function getFactory(): NewsFactory
{
return $this->factory;

+ 6
- 0
Container/Site/PageContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Site;

use App\Entity\Site\Page;
use Lc\SovBundle\Definition\Field\Site\PageFieldDefinition;
use Lc\SovBundle\Factory\Site\PageFactory;
use Lc\SovBundle\Repository\Site\PageRepositoryQuery;
@@ -26,6 +27,11 @@ class PageContainer
$this->fieldDefinition = $fieldDefinition;
}

public static function getEntityFqcn()
{
return Page::class;
}

public function getFactory(): PageFactory
{
return $this->factory;

+ 5
- 0
Container/Site/SiteContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Site;

use App\Entity\Site\Site;
use Lc\SovBundle\Factory\Site\SiteFactory;
use Lc\SovBundle\Repository\Site\SiteRepositoryQuery;
use Lc\SovBundle\Repository\Site\SiteStore;
@@ -22,6 +23,10 @@ class SiteContainer
$this->store = $store;
}

public static function getEntityFqcn()
{
return Site::class;
}
public function getFactory(): SiteFactory
{
return $this->factory;

+ 7
- 0
Container/Ticket/TicketContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Ticket;

use App\Entity\Ticket\Ticket;
use Lc\SovBundle\Builder\Ticket\TicketBuilder;
use Lc\SovBundle\Definition\Field\Ticket\TicketFieldDefinition;
use Lc\SovBundle\Factory\Ticket\TicketFactory;
@@ -34,6 +35,12 @@ class TicketContainer
$this->fieldDefinition = $fieldDefinition;
}


public static function getEntityFqcn()
{
return Ticket::class;
}

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

+ 5
- 0
Container/Ticket/TicketMessageContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\Ticket;

use App\Entity\Ticket\TicketMessage;
use Lc\SovBundle\Builder\Ticket\TicketMessageBuilder;
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory;
use Lc\SovBundle\Repository\Ticket\TicketMessageRepositoryQuery;
@@ -26,6 +27,10 @@ class TicketMessageContainer
$this->builder = $builder;
}

public static function getEntityFqcn()
{
return TicketMessage::class;
}
public function getFactory(): TicketMessageFactory
{
return $this->factory;

+ 5
- 0
Container/User/GroupUserContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\User;

use App\Entity\User\GroupUser;
use Lc\SovBundle\Factory\User\GroupUserFactory;
use Lc\SovBundle\Repository\User\GroupUserRepositoryQuery;
use Lc\SovBundle\Repository\User\GroupUserStore;
@@ -22,6 +23,10 @@ class GroupUserContainer
$this->store = $store;
}

public static function getEntityFqcn()
{
return GroupUser::class;
}
public function getFactory(): GroupUserFactory
{
return $this->factory;

+ 5
- 0
Container/User/UserContainer.php ファイルの表示

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

namespace Lc\SovBundle\Container\User;

use App\Entity\User\User;
use Lc\SovBundle\Builder\User\UserBuilder;
use Lc\SovBundle\Definition\Field\User\UserFieldDefinition;
use Lc\SovBundle\Definition\RolesDefinitionInterface;
@@ -37,6 +38,10 @@ class UserContainer
$this->fieldDefinition = $fieldDefinition;
$this->rolesDefinition = $rolesDefinition;
}
public static function getEntityFqcn()
{
return User::class;
}

public function getFactory(): UserFactory
{

+ 99
- 50
Controller/AbstractAdminController.php ファイルの表示

@@ -23,6 +23,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory;
@@ -36,9 +37,11 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\CaracoleBundle\Model\Section\SectionInterface;
use Lc\SovBundle\Component\EntityComponent;
use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
use Lc\SovBundle\Doctrine\Extension\SeoInterface;
use Lc\SovBundle\Doctrine\Extension\SortableInterface;
use Lc\SovBundle\Doctrine\Extension\StatusInterface;
@@ -46,6 +49,7 @@ use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
use Lc\SovBundle\Doctrine\Extension\TreeInterface;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Field\ImageManagerField;
use Lc\SovBundle\Form\Common\FiltersFormType;
use Lc\SovBundle\Form\Common\PositionType;
use Lc\SovBundle\Model\User\UserInterface;
@@ -58,6 +62,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;

abstract class AbstractAdminController extends EaAbstractCrudController
{
@@ -80,7 +85,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
$responseParameters->set('fields', $this->configureFields('index'));

if(isset($this->filtersForm)) {
if (isset($this->filtersForm)) {
$responseParameters->set('filters_form', $this->filtersForm);
}
}
@@ -136,10 +141,10 @@ abstract class AbstractAdminController extends EaAbstractCrudController
if ($action->getName() == ActionDefinition::WRITE_TO_USER) {
$entity = $context->getEntity()->getInstance();
if ($entity !== null) {
if(method_exists($entity, 'getUser')){
$url = $this->generateEaUrl(UserA) ->setController($context->getCrud()->getControllerFqcn())
->set('entityId', $entity->getParent()->getId())
->generateUrl();
if (method_exists($entity, 'getUser')) {
$url = $this->generateEaUrl(UserA)->setController($context->getCrud()->getControllerFqcn())
->set('entityId', $entity->getParent()->getId())
->generateUrl();
$action->setLinkUrl($url);
}
} else {
@@ -150,16 +155,17 @@ abstract class AbstractAdminController extends EaAbstractCrudController
}
}

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

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

@@ -167,7 +173,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController

if ($this->isInstanceOf(SortableInterface::class)) {
$crud->setDefaultSort(['position' => 'ASC']);
}else{
} else {
$crud->setDefaultSort(['id' => 'DESC']);
}

@@ -276,14 +282,15 @@ abstract class AbstractAdminController extends EaAbstractCrudController
throw new InsufficientEntityPermissionException($context);
}

$event = new BeforeEntityDeletedEvent($entityInstance);
$event = new BeforeEntityUpdatedEvent($entityInstance);
$this->get('event_dispatcher')->dispatch($event);
$entityInstance = $event->getEntityInstance();

$entityInstance->setPosition($elm['position']);
$this->updateEntity($entityManager, $entityInstance);

$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
// @TODO : ce dispatch déclenche UpdateProductfamilyAfterFlushEventSubscriber dans Caracole et on tombe sur une erreur "Maximum execution time"
//$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
}

$url = $this->get(AdminUrlGenerator::class)
@@ -319,14 +326,15 @@ abstract class AbstractAdminController extends EaAbstractCrudController
}

public function duplicate(
AdminContext $context,
EntityComponent $entityComponent,
TranslatorAdmin $translatorAdmin,
AdminContext $context,
EntityComponent $entityComponent,
TranslatorAdmin $translatorAdmin,
EntityManagerInterface $em
) {
)
{
if (!$this->isGranted(
Permission::EA_EXECUTE_ACTION,
['action' => "duplicate", 'entity' => $context->getEntity()]
['action' => ActionDefinition::DUPLICATE, 'entity' => $context->getEntity()]
)) {
throw new ForbiddenActionException($context);
}
@@ -336,7 +344,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
}

$newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance());
$em->create($newEntity);
$em->create($newEntity, false);
$em->flush();

$url = $this->get(AdminUrlGenerator::class)
@@ -344,24 +352,27 @@ abstract class AbstractAdminController extends EaAbstractCrudController
->setEntityId($newEntity->getId())
->generateUrl();

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

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

public function isRepositoryQueryFiltered():bool{
if(($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered){
public function isRepositoryQueryFiltered(): bool
{
if (($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered) {
return true;
}else{
} else {
return false;
}
}

public function createIndexRepositoryQuery(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): RepositoryQueryInterface {
): RepositoryQueryInterface
{
$repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
$this->getRepositoryQuery(),
$searchDto,
@@ -402,29 +413,38 @@ abstract class AbstractAdminController extends EaAbstractCrudController


public function createSortRepositoryQuery(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): RepositoryQueryInterface {
return $this->createIndexRepositoryQuery($searchDto,$entityDto, $fields, $filters);
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): RepositoryQueryInterface
{
$repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
if ($this->isInstanceOf(StatusInterface::class)) {
$repositoryQuery->filterIsOnline();
}
$repositoryQuery->orderBy('position', 'asc');
return $repositoryQuery;
}

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

public function createSortQueryBuilder(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): QueryBuilder {
): QueryBuilder
{
$repositoryQuery = $this->createSortRepositoryQuery($searchDto, $entityDto, $fields, $filters);
return $repositoryQuery->getQueryBuilder();
}
@@ -466,7 +486,12 @@ abstract class AbstractAdminController extends EaAbstractCrudController

public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
$entityManager->delete($entityInstance);
if ($this->isInstanceOf(StatusInterface::class)) {
$entityInstance->setStatus(-1);
$entityManager->update($entityInstance);
} else {
$entityManager->delete($entityInstance);
}
$entityManager->flush();
$this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName());
}
@@ -762,12 +787,18 @@ abstract class AbstractAdminController extends EaAbstractCrudController

public function autocompleteFilter(AdminContext $context): JsonResponse
{
$queryBuilder = $this->createIndexQueryBuilder(
$repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
$this->getRepositoryQuery(),
$context->getSearch(),
$context->getEntity(),
FieldCollection::new([]),
FilterCollection::new()
);

if ($this->isInstanceOf(StatusInterface::class)) {
$repositoryQuery->filterIsOnlineAndOffline();
}

$autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT);

/** @var CrudControllerInterface $controller */
@@ -782,20 +813,15 @@ abstract class AbstractAdminController extends EaAbstractCrudController
)->getByProperty($autocompleteContext['propertyName']);

$filterManager = $this->get(FilterManager::class);

$filterManager->applyFilter($queryBuilder, $field, $context->getRequest()->query->get('q'));
if ($filterManager->isRelationField($field->getProperty())) {
$queryBuilder->select($autocompleteContext['propertyName']);
} else {
$queryBuilder->select('entity.' . $autocompleteContext['propertyName']);
}
$filteredValue = ['value' => $context->getRequest()->query->get('q')];
$filterManager->applyFilter($repositoryQuery, $field, $filteredValue);
$repositoryQuery->select('.' . $autocompleteContext['propertyName']);

$responses = array();
foreach ($queryBuilder->getQuery()->getArrayResult() as $result) {
foreach ($repositoryQuery->find() as $result) {
$responses[] = array_values($result)[0];
}


return JsonResponse::fromJsonString(json_encode($responses));
}

@@ -816,5 +842,28 @@ abstract class AbstractAdminController extends EaAbstractCrudController
return $this->createForm($class, $data, $options);
}

public function eaBeforeCrudActionEventDelete(AdminContext $context): ?Response
{
$event = new BeforeCrudActionEvent($context);
$this->container->get('event_dispatcher')->dispatch($event);
if ($event->isPropagationStopped()) {
return $event->getResponse();
}

if (!$this->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => Action::DELETE, 'entity' => $context->getEntity()])) {
throw new ForbiddenActionException($context);
}
if (!$context->getEntity()->isAccessible()) {
throw new InsufficientEntityPermissionException($context);
}

$csrfToken = $context->getRequest()->request->get('token');

if (!$this->isCsrfTokenValid('ea-delete', $csrfToken)) {
return $this->redirectToRoute($context->getDashboardRouteName());
}
return null;
}

}


+ 81
- 48
Controller/ControllerTrait.php ファイルの表示

@@ -18,7 +18,9 @@ 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\Definition\ApplicationDefinition;
use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Generator\PdfGenerator;
use Lc\SovBundle\Repository\EntityRepository;
use Lc\SovBundle\Solver\Setting\SettingSolver;
use Lc\SovBundle\Translation\FlashBagTranslator;
@@ -30,70 +32,76 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;

trait ControllerTrait
{
public static function getSubscribedServices()
/*
* Fonctions privées
*/
protected function _setNoLimitMemoryAndTime()
{
ini_set('memory_limit', '-1');
set_time_limit(0);
}

//TODO si vous avez une erreur avec le :array c'est qu'il faut passer à symfony 5.4.
//Suivez la procédure suivante : https://symfony.com/doc/current/setup/unstable_versions.html#upgrading-your-project-to-an-unstable-symfony-version
//En gros il faut changer tout les dépendances symfony/ qui sont en 5.3 par 5.4 dans composer.json
public static function getSubscribedServices(): array
{
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,
]
parent::getSubscribedServices(),
ApplicationDefinition::getSubscribedContainerServices(),
[
ApplicationDefinition::class => ApplicationDefinition::class,
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,
PdfGenerator::class => PdfGenerator::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,
EntityRepository::class => EntityRepository::class,
FileComponent::class => FileComponent::class,
KernelInterface::class => KernelInterface::class
]
);
}

public function addFlashTranslator(
string $type,
$translationKeyName,
$translationEntityName = null,
$translationParam = array()
): void
{
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
$type,
$translationKeyName,
$translationEntityName,
$translationParam
);
}

@@ -102,8 +110,12 @@ trait ControllerTrait
return in_array($interfaceName, class_implements($this->getEntityFqcn()));
}

public function generateEaUrl(string $controller = null, string $action = null, int $entityId = null, array $extraParam = array()): string
{
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);
@@ -132,6 +144,11 @@ trait ControllerTrait
return $this->get(Environment::class);
}

public function getApplicationDefinition(): ApplicationDefinition
{
return $this->get(ApplicationDefinition::class);
}

public function getEntityManager(): EntityManagerInterface
{
return $this->get(EntityManagerInterface::class);
@@ -177,6 +194,11 @@ trait ControllerTrait
return $this->get(TranslatorInterface::class);
}

public function getPdfGenerator(): PdfGenerator
{
return $this->get(PdfGenerator::class);
}

public function getTranslatorAdmin(): TranslatorAdmin
{
return $this->get(TranslatorAdmin::class);
@@ -197,6 +219,11 @@ trait ControllerTrait
return $this->get(AdminUrlGenerator::class);
}

public function getKernel(): KernelInterface
{
return $this->get(KernelInterface::class);
}

public function getSettingSolver(): SettingSolver
{
return $this->get(SettingSolver::class);
@@ -267,4 +294,10 @@ trait ControllerTrait
return $this->get(SiteSettingContainer::class);
}

}
public function setNoMemoryAndTimeLimit(): void
{
ini_set('memory_limit', '-1');
set_time_limit(0);
}

}

+ 50
- 0
Controller/Dashboard/CommandAdminController.php ファイルの表示

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

namespace Lc\SovBundle\Controller\Dashboard;

use Lc\SovBundle\Controller\ControllerTrait;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class CommandAdminController extends AbstractController
{
use ControllerTrait;

/**
* @Route("/admin/command/cache/clear", name="admin_command_cache_clear")
*/
public function cacheClear(Request $request)
{
$this->doCommand('cache:clear');

$this->addFlashTranslator('success', 'command.cacheClear');

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

private function doCommand($command)
{
$kernel = $this->getKernel();
$env = $kernel->getEnvironment();

$application = new Application($kernel);
$application->setAutoExit(false);

$input = new ArrayInput(array(
'command' => $command,
'--env' => $env
));

$output = new BufferedOutput();
$application->run($input, $output);

$content = $output->fetch();

//return new Response($content);
}
}

+ 3
- 2
Controller/Dashboard/DashboardAdminController.php ファイルの表示

@@ -19,6 +19,9 @@ class DashboardAdminController extends AbstractDashboardController

use ControllerTrait;

/**
* @Route("/admin", name="app_admin_dashboard")
*/
public function index(): Response
{
return $this->render('@LcSov/adminlte/dashboard.html.twig');
@@ -29,8 +32,6 @@ class DashboardAdminController extends AbstractDashboardController
return Dashboard::new()
// the name visible to end users
->setTitle('LA CLIC !')
// 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('assets/img/frontend/favicon-pdl.png')
// the domain used by default is 'messages'

+ 43
- 5
Controller/ErrorController.php ファイルの表示

@@ -2,22 +2,60 @@

namespace Lc\SovBundle\Controller;

use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mailer\MailerInterface;
use Throwable;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\Mime\Email;

class ErrorController extends AbstractController
{

public function show(Throwable $exception, DebugLoggerInterface $logger = null)
{
if ($this->getRequestStack()->getCurrentRequest()->getPathInfo() == "/admin") {
public function show(
Request $request,
FlattenException $exception,
DebugLoggerInterface $logger = null,
MailerInterface $mailer
) {
//Si != de 404 on envoit un mail de debug
if ($exception->getStatusCode() != 404) {
$mailDebug = $this->getParameter('app.mail_debug');
if ($mailDebug) {
$message = "URL : " . $request->getUri() . "<br>";
$message .= "Code : " . $exception->getStatusCode() . "<br>";
$message .= "Message : " . $exception->getMessage() . "<br>";
$message .= "File : " . $exception->getFile() . "<br>";
$message .= "Line : " . $exception->getLine() . "<br><br>";
$message .= "Trace : <br>" . str_replace("\n", "<br>", $exception->getTraceAsString());
$siteName = $this->getParameter('app.site_name');
$email = (new Email())
->from('nepasrepondre@laclic.fr')
->to($mailDebug)
->subject(
'[' . $siteName . '] [ERREUR ' . $exception->getStatusCode() . '] ' . $exception->getMessage() . ''
)
->text(strip_tags($message))
->html($message);

$mailer->send($email);
}
}

if ($exception->getStatusCode() == 404) {
return $this->render('bundles/TwigBundle/Exception/error404.html.twig', [
"code" => $exception->getStatusCode(),
"message" => $exception->getMessage()
]);
}
if (str_contains($this->getRequestStack()->getCurrentRequest(), "/admin")) {
return $this->render('@LcSov/exception/error.html.twig', [
"code" => $exception->getCode(),
"code" => $exception->getStatusCode(),
"message" => $exception->getMessage()
]);
} else {
return $this->render('bundles/TwigBundle/Exception/error.html.twig', [
"code" => $exception->getCode(),
"code" => $exception->getStatusCode(),
"message" => $exception->getMessage()
]);
}

+ 4
- 4
Controller/Security/SecurityAdminController.php ファイルの表示

@@ -40,7 +40,7 @@ class SecurityAdminController extends AbstractController
// 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') . '" >',
'page_title' => '<img class="logo-admin" src="assets/img/' . $this->getParameter('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
@@ -50,13 +50,13 @@ class SecurityAdminController extends AbstractController
'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',
'username_label' => 'Email',

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

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

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

+ 120
- 0
Controller/User/UserAdminController.php ファイルの表示

@@ -2,20 +2,36 @@

namespace Lc\SovBundle\Controller\User;

use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\ORM\EntityManagerInterface;
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\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\EntityRemoveException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Definition\ApplicationDefinition;
use Lc\SovBundle\Definition\RolesDefinition;
use Lc\SovBundle\Definition\RolesDefinitionInterface;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Factory\User\UserFactory;
use Lc\SovBundle\Form\User\ConfirmDeleteUserFormType;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
@@ -76,4 +92,108 @@ abstract class UserAdminController extends AbstractAdminController
{
return $this->get(UserContainer::class)->getFactory()->create();
}

public function delete(AdminContext $context)
{
$entityManager = $this->getEntityManager();

// Todo envisager un refactor similaire pour toutes les fonctions CRUD
$eaBeforeCrudActionEventDelete = $this->eaBeforeCrudActionEventDelete($context);
if (!is_null($eaBeforeCrudActionEventDelete)) {
return $eaBeforeCrudActionEventDelete;
}

$user = $context->getEntity()->getInstance();

$event = new BeforeEntityDeletedEvent($user);
$this->container->get('event_dispatcher')->dispatch($event);
if ($event->isPropagationStopped()) {
return $event->getResponse();
}

$user = $event->getEntityInstance();


// Creéer formulaire avec un champ confirm
$confirmDeleteUserForm = $this->createForm(ConfirmDeleteUserFormType::class, null, array(
'action' => $this->getAdminUrlGenerator()->generateUrl()
));
$confirmDeleteUserForm->handleRequest($context->getRequest());

$entityManager->delete($user);

$warningMessages = $this->getDeleteUserWarningMessageList($user);

//Avant la suppression on s'assure que l'utilisateur à confirmer et qu'il n'y aucun message d'erreur
if ($confirmDeleteUserForm->isSubmitted() && count($warningMessages['danger']) === 0) {
//Détecter les tables qui possède des relations avec un champ qui n'existe plus
//Dans le cas ci-dessous détecter les adresses lié à un utilisateur qui n'existe plus
//SELECT * FROM address a LEFT OUTER JOIN user u ON(u.id=a.user_id) WHERE u.id is null
try {
$entityManager->flush();
$this->addFlashTranslator('success', 'deleted');
} catch (ForeignKeyConstraintViolationException $e) {
throw new EntityRemoveException(['entity_name' => $context->getEntity()->getName(), 'message' => $e->getMessage()]);
}
return $this->redirect($this->getAdminUrlGenerator()->setAction(Crud::PAGE_INDEX)->setEntityId(null)->generateUrl());

}else{
if($confirmDeleteUserForm->isSubmitted()){
$this->addFlashTranslator('error', 'cannotDelete');
}
}

$responseParameters = $this->configureResponseParameters(KeyValueStore::new([
'pageName' => Crud::PAGE_DETAIL,
'templatePath' => '@LcSov/adminlte/crud/delete.html.twig',
'confirm_delete_user_form' => $confirmDeleteUserForm->createView(),
'global_actions' => array(),
'batch_actions' => array(),
'warning_message_list' => $warningMessages
]));

$event = new AfterCrudActionEvent($context, $responseParameters);
$this->get('event_dispatcher')->dispatch($event);
if ($event->isPropagationStopped()) {
return $event->getResponse();
}

return $responseParameters;
}

public function getDeleteUserWarningMessageList(UserInterface $user): array
{
$warningMessages = array();
$warningMessages['danger'] = [];
$warningMessages['warning'] = [];
$warningMessages['info'] = [];


$entityManager = $this->getEntityManager();

$entityToDeleteListCount = array();
$entityToDeleteListName = array();
foreach ($entityManager->getUnitOfWork()->getScheduledEntityDeletions() as $entityToDelete) {
if (isset($entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()])) {
$entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()]++;
} else {
$entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()] = 1;
}
$entityToDeleteListName[(new \ReflectionClass($entityToDelete))->getShortName()][] = $entityToDelete->getId();
}

foreach ($entityToDeleteListCount as $entityName => $entityToDeleteCount) {
$warningMessages['info'][] = $this->getTranslatorAdmin()->transFlashMessage(
'error',
'deleteEntityCascade',
'User',
array(
'%entity%' => $this->getTranslatorAdmin()->trans('entity.'.$entityName.'.label_plurial'),
'%count%' => $entityToDeleteCount
)
);
}

return $warningMessages;
}
}

+ 88
- 0
Definition/ApplicationDefinition.php ファイルの表示

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

namespace Lc\SovBundle\Definition;

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 function Symfony\Component\String\u;

class ApplicationDefinition
{

public static function getContainerList(): array
{
return [
FileContainer::class,
NewsletterContainer::class,
ReminderContainer::class,
NewsContainer::class,
PageContainer::class,
SiteContainer::class,
TicketContainer::class,
TicketMessageContainer::class,
GroupUserContainer::class,
UserContainer::class,
SiteSettingContainer::class,
ComponentContainer::class
];
}

public function getContainerByEntityFqcn(string $entityFqcn)
{
foreach (static::getContainerList() as $containerFqcn){
if($this->isContainerManageEntity($containerFqcn)){
if ($containerFqcn::getEntityFqcn() == $entityFqcn) {
return $containerFqcn;
}
}
}
return null;
}

public function isContainerManageEntity(string $containerFqcn)
{
if(method_exists($containerFqcn, 'getEntityFqcn') ){
return true;
}
return false;
}

public static function getSubscribedContainerServices(): array
{
$array = [];


foreach (static::getContainerList() as $container) {
$array[$container] = $container;
}

return $array;
}


public static function getContainerListForTwigGlobals(): array
{
$array = [];

foreach (static::getContainerList() as $containerNamespace) {
//récupère le nom du fichier dans le namespace du container
$key = u(substr($containerNamespace, strrpos($containerNamespace, '\\')))->snake();

$array[$key->toString()] = '@' . $containerNamespace;
}

return $array;
}


}

+ 16
- 7
Definition/Field/AbstractFieldDefinition.php ファイルの表示

@@ -8,6 +8,8 @@ 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\AssociationField;
use Lc\SovBundle\Field\CKEditorField;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\ImageManagerField;
use Lc\SovBundle\Field\StatusField;
@@ -29,26 +31,33 @@ abstract class AbstractFieldDefinition
{
return [
'id' => IntegerField::new('id')->onlyOnIndex()->setSortable(true),
'title' => TextField::new('title'),
'description' => CKEditorField::new('description'),
'image' => ImageManagerField::new('image'),
'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(),
'openGraphTitle' => TextField::new('openGraphTitle')
->setLabel('OpenGraph : titre')
->setHelp('Utilisé par les réseaux sociaux pour récupérer le titre de la page'),
'openGraphDescription' => TextareaField::new('openGraphDescription')
->setLabel('OpenGraph : description')
->setHelp('Utilisé par les réseaux sociaux pour récupérer la description de la page'),
'openGraphImage' => ImageManagerField::new('openGraphImage')
->setLabel('OpenGraph : image'),
'devAlias' => TextField::new('devAlias')->hideOnIndex(),
'status' => StatusField::new('status')->setSortable(true),
'createdAt' => DateTimeField::new('createdAt')->setSortable(true),
'updatedAt' => DateTimeField::new('updatedAt')->setSortable(true),
'createdBy' => AssociationField::new('createdBy'),
'updatedBy' => AssociationField::new('updatedBy')
];
}

@@ -137,7 +146,7 @@ abstract class AbstractFieldDefinition
$fieldArray = [];
foreach($configureFieldArray as $fieldName) {
if(isset($allFieldArray[$fieldName])) {
$fieldArray[] = $allFieldArray[$fieldName];
$fieldArray[$fieldName] = $allFieldArray[$fieldName];
}
else {
throw new \ErrorException('Le field "'.$fieldName.'" n\'est pas défini dans configureFields()');

+ 2
- 2
Definition/Field/Site/PageFieldDefinition.php ファイルの表示

@@ -18,7 +18,7 @@ class PageFieldDefinition extends AbstractFieldDefinition
];
}

public function configurePanelMain(): array
public function configurePanelGeneral(): array
{
return [
'title',
@@ -29,7 +29,7 @@ class PageFieldDefinition extends AbstractFieldDefinition

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

public function configureFields(): array

+ 13
- 13
Definition/SiteSettingDefinition.php ファイルの表示

@@ -19,28 +19,28 @@ class SiteSettingDefinition extends AbstractSettingDefinition implements SiteSet
{
// général
$this->addSettingSelect(
[
'category' => self::CATEGORY_GENERAL,
'name' => self::SETTING_MAINTENANCE,
'choices' => [
'Non' => 0,
'Oui' => 1,
]
[
'category' => self::CATEGORY_GENERAL,
'name' => self::SETTING_MAINTENANCE,
'choices' => [
'Non' => 0,
'Oui' => 1,
]
]
);

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

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


+ 1
- 1
Definition/SiteSettingDefinitionInterface.php ファイルの表示

@@ -4,5 +4,5 @@ namespace Lc\SovBundle\Definition;

interface SiteSettingDefinitionInterface
{
public function getCategories(): array;
}

+ 21
- 16
DependencyInjection/LcSovExtension.php ファイルの表示

@@ -9,26 +9,31 @@ use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;


class LcSovExtension extends Extension implements PrependExtensionInterface
class LcSovExtension extends Extension implements PrependExtensionInterface
{


public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

foreach ($config as $parameter => $value)
$container->setParameter(sprintf('lc_sov.%s', $parameter), $value);

$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yaml');
foreach ($config as $parameter => $value) {
$container->setParameter(sprintf('lc_sov.%s', $parameter), $value);
}

public function prepend(ContainerBuilder $container)
{
/*$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/easy_admin'));
$loader->load('base.yaml');
$loader->load('entities/merchant.yaml');*/
}
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));

$loader->load('services.yaml');
}

public function prepend(ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/packages'));
$loader->load('ch_cookie_consent.yaml');

/*$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/easy_admin'));
$loader->load('base.yaml');
$loader->load('entities/merchant.yaml');*/
}
}

+ 9
- 1
Doctrine/Extension/BlameableInterface.php ファイルの表示

@@ -3,8 +3,16 @@
namespace Lc\SovBundle\Doctrine\Extension;


use Lc\SovBundle\Model\User\UserInterface;

interface BlameableInterface
{

public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy): BlameableInterface;

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy): BlameableInterface;
}

+ 2
- 2
Doctrine/Extension/BlameableTrait.php ファイルの表示

@@ -12,14 +12,14 @@ trait BlameableTrait
/**
* @Gedmo\Blameable(on="create")
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface")
* @ORM\JoinColumn(nullable=true)
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
protected $createdBy;

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


+ 2
- 0
Doctrine/Extension/DevAliasInterface.php ファイルの表示

@@ -4,5 +4,7 @@ namespace Lc\SovBundle\Doctrine\Extension;

interface DevAliasInterface
{
public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias): DevAliasInterface;
}

+ 26
- 0
Doctrine/Extension/ImageTrait.php ファイルの表示

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

namespace Lc\SovBundle\Doctrine\Extension;

use App\Entity\File\File;
use Doctrine\ORM\Mapping as ORM;

trait ImageTrait
{
/**
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\File\FileInterface", cascade={"persist", "remove"}, fetch="EAGER")
*/
protected $image;

public function getImage(): ?File
{
return $this->image;
}

public function setImage(?File $image): self
{
$this->image = $image;

return $this;
}
}

+ 10
- 0
Doctrine/Extension/OpenGraphInterface.php ファイルの表示

@@ -2,9 +2,19 @@

namespace Lc\SovBundle\Doctrine\Extension;

use Lc\SovBundle\Model\File\FileInterface;

interface OpenGraphInterface
{
public function getOpenGraphTitle(): ?string;

public function setOpenGraphTitle(string $openGraphTitle): OpenGraphInterface;

public function getOpenGraphDescription(): ?string;

public function setOpenGraphDescription(?string $openGraphDescription): OpenGraphInterface;

public function getOpenGraphImage(): ?FileInterface;

public function setOpenGraphImage(?FileInterface $openGraphImage);
}

+ 2
- 2
Doctrine/Extension/OpenGraphTrait.php ファイルの表示

@@ -48,12 +48,12 @@ trait OpenGraphTrait
}


public function getOpenGraphImage(): ?FileModel
public function getOpenGraphImage(): ?FileInterface
{
return $this->openGraphImage;
}

public function setOpenGraphImage(?FileModel $openGraphImage): self
public function setOpenGraphImage(?FileInterface $openGraphImage): self
{
$this->openGraphImage = $openGraphImage;


+ 8
- 0
Doctrine/Extension/SeoInterface.php ファイルの表示

@@ -4,7 +4,15 @@ namespace Lc\SovBundle\Doctrine\Extension;

interface SeoInterface
{
public function getMetaTitle(): ?string;

public function setMetaTitle(?string $metaTitle): SeoInterface;

public function getMetaDescription(): ?string;

public function setMetaDescription(?string $metaDescription): SeoInterface;

public function getOldUrls(): ?array;

public function setOldUrls($oldUrls): SeoInterface;
}

+ 3
- 0
Doctrine/Extension/SluggableInterface.php ファイルの表示

@@ -5,4 +5,7 @@ namespace Lc\SovBundle\Doctrine\Extension;
interface SluggableInterface
{

public function getSlug(): ?string;

public function setSlug(?string $slug): SluggableInterface;
}

+ 5
- 0
Doctrine/Extension/SortableInterface.php ファイルの表示

@@ -5,4 +5,9 @@ namespace Lc\SovBundle\Doctrine\Extension;
interface SortableInterface
{

public function getPosition(): float;

public function setPosition(float $position): SortableInterface;

public function clearPosition(): SortableInterface;
}

+ 4
- 0
Doctrine/Extension/StatusInterface.php ファイルの表示

@@ -5,4 +5,8 @@ namespace Lc\SovBundle\Doctrine\Extension;
interface StatusInterface
{

public function getStatus(): ?float;

public function setStatus(float $status): StatusInterface;

}

+ 6
- 0
Doctrine/Extension/TimestampableInterface.php ファイルの表示

@@ -4,6 +4,12 @@ namespace Lc\SovBundle\Doctrine\Extension;

interface TimestampableInterface
{
public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt): TimestampableInterface;

public function getUpdatedAt(): ?\DateTimeInterface;

public function setUpdatedAt(\DateTimeInterface $updatedAt): TimestampableInterface;

}

+ 5
- 1
Doctrine/Extension/TranslatableInterface.php ファイルの表示

@@ -4,6 +4,10 @@ namespace Lc\SovBundle\Doctrine\Extension;

interface TranslatableInterface
{

public function setTranslatableLocale($locale);

public function getLocalesEnabled(): ?array;

public function setLocalesEnabled(?array $localesEnabled): TranslatableInterface;
}

+ 4
- 1
Doctrine/Pattern/AbstractFullEntity.php ファイルの表示

@@ -7,6 +7,8 @@ use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Doctrine\Extension\BlameableTrait;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\DevAliasTrait;
use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
use Lc\SovBundle\Doctrine\Extension\OpenGraphTrait;
use Lc\SovBundle\Doctrine\Extension\SeoInterface;
use Lc\SovBundle\Doctrine\Extension\SeoTrait;
use Lc\SovBundle\Doctrine\Extension\SluggableInterface;
@@ -24,12 +26,13 @@ use Lc\SovBundle\Doctrine\Extension\TimestampableTrait;
/**
* @ORM\MappedSuperclass
*/
abstract class AbstractFullEntity implements BlameableInterface, SeoInterface, SluggableInterface, SortableInterface,
abstract class AbstractFullEntity implements BlameableInterface, SeoInterface, OpenGraphInterface, SluggableInterface, SortableInterface,
StatusInterface, TimestampableInterface, DevAliasInterface, EntityInterface
{

use BlameableTrait;
use SeoTrait;
use OpenGraphTrait;
use SluggableTrait;
use SortableTrait;
use StatusTrait;

+ 5
- 3
EventListener/ExceptionListener.php ファイルの表示

@@ -22,9 +22,11 @@ class ExceptionListener

// On détecte une erreur interne (500), on remove les sessions qui servent de filtre dans l'admin
if ($exception instanceof HttpExceptionInterface != true) {
foreach ($this->session->all() as $key => $s) {
if (str_contains($key, "_filter")) {
$this->session->remove($key);
if (!headers_sent()) {
foreach ($this->session->all() as $key => $s) {
if (str_contains($key, "_filter")) {
$this->session->remove($key);
}
}
}
}

+ 3
- 2
Factory/File/FileFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\File;

use App\Entity\File\File;
use Lc\SovBundle\Container\File\FileContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\File\FileInterface;

@@ -10,7 +10,8 @@ class FileFactory extends AbstractFactory
{
public function create(): FileInterface
{
$file = new File();
$class = FileContainer::getEntityFqcn();
$file = new $class;

return $file;
}

+ 3
- 2
Factory/Newsletter/NewsletterFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Newsletter;

use App\Entity\Newsletter\Newsletter;
use Lc\SovBundle\Container\Newsletter\NewsletterContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;

@@ -10,7 +10,8 @@ class NewsletterFactory extends AbstractFactory
{
public function create(): NewsletterInterface
{
$newsletter = new Newsletter();
$class = NewsletterContainer::getEntityFqcn();
$newsletter = new $class;

return $newsletter;
}

+ 3
- 3
Factory/Reminder/ReminderFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Reminder;

use App\Entity\Reminder\Reminder;
use Lc\SovBundle\Container\Reminder\ReminderContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Reminder\ReminderInterface;

@@ -13,8 +13,8 @@ class ReminderFactory extends AbstractFactory implements ReminderFactoryInterfac
string $crudControllerFqcn = null,
int $entityId = null
): ReminderInterface {
$reminder = new Reminder();
$class = ReminderContainer::getEntityFqcn();
$reminder = new $class;
$reminder->setCrudAction($crudAction);
$reminder->setCrudControllerFqcn($crudControllerFqcn);
$reminder->setEntityId($entityId);

+ 7
- 1
Factory/Reminder/ReminderFactoryInterface.php ファイルの表示

@@ -2,7 +2,13 @@

namespace Lc\SovBundle\Factory\Reminder;

use Lc\SovBundle\Model\Reminder\ReminderInterface;

interface ReminderFactoryInterface
{

public function create(
string $crudAction = null,
string $crudControllerFqcn = null,
int $entityId = null
): ReminderInterface;
}

+ 3
- 2
Factory/Setting/SiteSettingFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Setting;

use App\Entity\Setting\SiteSetting;
use Lc\SovBundle\Container\Setting\SiteSettingContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Model\Setting\SiteSettingInterface;
@@ -12,7 +12,8 @@ class SiteSettingFactory extends AbstractFactory implements SiteSettingFactoryIn
{
public function create(SiteInterface $site, string $name, string $text = null, \DateTime $date = null, FileInterface $file = null): SiteSettingInterface
{
$siteSetting = new SiteSetting();
$class = SiteSettingContainer::getEntityFqcn();
$siteSetting = new $class;

$siteSetting->setSite($site);
$siteSetting->setName($name);

+ 11
- 1
Factory/Setting/SiteSettingFactoryInterface.php ファイルの表示

@@ -2,7 +2,17 @@

namespace Lc\SovBundle\Factory\Setting;

use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Model\Setting\SiteSettingInterface;
use Lc\SovBundle\Model\Site\SiteInterface;

interface SiteSettingFactoryInterface
{

public function create(
SiteInterface $site,
string $name,
string $text = null,
\DateTime $date = null,
FileInterface $file = null
): SiteSettingInterface;
}

+ 3
- 3
Factory/Site/NewsFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Site;

use App\Entity\Site\News;
use Lc\SovBundle\Container\Site\NewsContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Site\NewsInterface;

@@ -10,8 +10,8 @@ class NewsFactory extends AbstractFactory implements NewsFactoryInterface
{
public function create(): NewsInterface
{
$news = new News();
$class = NewsContainer::getEntityFqcn();
$news = new $class;
$news->setStatus(1);

return $news;

+ 3
- 1
Factory/Site/NewsFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\Site;

use Lc\SovBundle\Model\Site\NewsInterface;

interface NewsFactoryInterface
{
public function create(): NewsInterface;
}

+ 3
- 2
Factory/Site/PageFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Site;

use App\Entity\Site\Page;
use Lc\SovBundle\Container\Site\PageContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Site\PageInterface;

@@ -10,7 +10,8 @@ class PageFactory extends AbstractFactory implements PageFactoryInterface
{
public function create(): PageInterface
{
$page = new Page();
$class = PageContainer::getEntityFqcn();
$page = new $class;

$page->setStatus(1);


+ 3
- 1
Factory/Site/PageFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\Site;

use Lc\SovBundle\Model\Site\PageInterface;

interface PageFactoryInterface
{
public function create(): PageInterface;
}

+ 3
- 2
Factory/Site/SiteFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Site;

use App\Entity\Site\Site;
use Lc\SovBundle\Container\Site\SiteContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Site\SiteInterface;

@@ -10,7 +10,8 @@ class SiteFactory extends AbstractFactory implements SiteFactoryInterface
{
public function create(string $devAlias = null): SiteInterface
{
$site = new Site();
$class = SiteContainer::getEntityFqcn();
$site = new $class;

$site->setDevAlias($devAlias);


+ 3
- 1
Factory/Site/SiteFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\Site;

use Lc\SovBundle\Model\Site\SiteInterface;

interface SiteFactoryInterface
{
public function create(string $devAlias = null): SiteInterface;
}

+ 3
- 2
Factory/Ticket/TicketFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Ticket;

use App\Entity\Ticket\Ticket;
use Lc\SovBundle\Container\Ticket\TicketContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketModel;
@@ -11,7 +11,8 @@ class TicketFactory extends AbstractFactory implements TicketFactoryInterface
{
public function create(): TicketInterface
{
$ticket = new Ticket();
$class = TicketContainer::getEntityFqcn();
$ticket = new $class;

$ticketMessageFactory = new TicketMessageFactory();
$ticketMessage = $ticketMessageFactory->create($ticket) ;

+ 3
- 1
Factory/Ticket/TicketFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\Ticket;

use Lc\SovBundle\Model\Ticket\TicketInterface;

interface TicketFactoryInterface
{
public function create(): TicketInterface;
}

+ 3
- 2
Factory/Ticket/TicketMessageFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\Ticket;

use App\Entity\Ticket\TicketMessage;
use Lc\SovBundle\Container\Ticket\TicketMessageContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
@@ -11,7 +11,8 @@ class TicketMessageFactory extends AbstractFactory implements TicketMessageFacto
{
public function create(TicketInterface $ticket): TicketMessageInterface
{
$ticketMessage = new TicketMessage();
$class = TicketMessageContainer::getEntityFqcn();
$ticketMessage = new $class;

$ticketMessage->setTicket($ticket);
$ticketMessage->setStatus(1);

+ 4
- 1
Factory/Ticket/TicketMessageFactoryInterface.php ファイルの表示

@@ -2,7 +2,10 @@

namespace Lc\SovBundle\Factory\Ticket;

use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;

interface TicketMessageFactoryInterface
{

public function create(TicketInterface $ticket): TicketMessageInterface;
}

+ 3
- 2
Factory/User/GroupUserFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\User;

use App\Entity\User\GroupUser;
use Lc\SovBundle\Container\User\GroupUserContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\User\GroupUserInterface;

@@ -10,7 +10,8 @@ class GroupUserFactory extends AbstractFactory implements GroupUserFactoryInterf
{
public function create(): GroupUserInterface
{
$groupUser = new GroupUser();
$class = GroupUserContainer::getEntityFqcn();
$groupUser = new $class;

$groupUser->setStatus(1);


+ 3
- 1
Factory/User/GroupUserFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\User;

use Lc\SovBundle\Model\User\GroupUserInterface;

interface GroupUserFactoryInterface
{
public function create(): GroupUserInterface;
}

+ 4
- 2
Factory/User/UserFactory.php ファイルの表示

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

namespace Lc\SovBundle\Factory\User;

use App\Entity\User\User;
use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\User\UserInterface;

@@ -10,7 +10,9 @@ class UserFactory extends AbstractFactory
{
public function create(): UserInterface
{
$user = new User();

$class = UserContainer::getEntityFqcn();
$user = new $class;

return $user;
}

+ 3
- 1
Factory/User/UserFactoryInterface.php ファイルの表示

@@ -2,7 +2,9 @@

namespace Lc\SovBundle\Factory\User;

use Lc\SovBundle\Model\User\UserInterface;

interface UserFactoryInterface
{
public function create(): UserInterface;
}

+ 149
- 0
Field/AssociationField.php ファイルの表示

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

namespace Lc\SovBundle\Field;

use Doctrine\ORM\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

final class AssociationField implements FieldInterface
{
use FieldTrait;

public const OPTION_AUTOCOMPLETE = 'autocomplete';
public const OPTION_CRUD_CONTROLLER = 'crudControllerFqcn';
public const OPTION_WIDGET = 'widget';
public const OPTION_QUERY_BUILDER_CALLABLE = 'queryBuilderCallable';
/** @internal this option is intended for internal use only */
public const OPTION_RELATED_URL = 'relatedUrl';
/** @internal this option is intended for internal use only */
public const OPTION_DOCTRINE_ASSOCIATION_TYPE = 'associationType';

public const WIDGET_AUTOCOMPLETE = 'autocomplete';
public const WIDGET_NATIVE = 'native';

/** @internal this option is intended for internal use only */
public const PARAM_AUTOCOMPLETE_CONTEXT = 'autocompleteContext';

protected $queryBuilderParameters = array();

/**
* @param string|false|null $label
*/
public static function new(string $propertyName, $label = null): self
{
return (new self())
->setProperty($propertyName)
->setLabel($label)
->setTemplatePath('@LcSov/adminlte/crud/field/association.html.twig')
->setFormType(EntityType::class)
->addCssClass('field-association')
->setCustomOption(self::OPTION_AUTOCOMPLETE, false)
->setCustomOption(self::OPTION_CRUD_CONTROLLER, null)
->setCustomOption(self::OPTION_WIDGET, self::WIDGET_AUTOCOMPLETE)
->setCustomOption(self::OPTION_QUERY_BUILDER_CALLABLE, null)
->setCustomOption(self::OPTION_RELATED_URL, '')
->setCustomOption(self::OPTION_DOCTRINE_ASSOCIATION_TYPE, null);
}

public function setFilterOnDevAlias(string $devAlias): self
{
$this->queryBuilderParameters['devAlias'] = $devAlias;

return $this;
}

public function setFilterIsOnline(): self
{
$this->queryBuilderParameters['status'] = 1;

return $this;
}

public function setLeftJoin($entityName): self
{
$this->queryBuilderParameters['leftJoin'][] = $entityName;

return $this;
}

public function addAndWhere($whereClause, $key, $value): self
{
$this->queryBuilderParameters['andWhere'][] = [
'whereClause' => $whereClause,
'key' => $key,
'value' => $value
];

return $this;
}

public function addOrderBy($field, $direction = 'ASC'): self
{
$this->queryBuilderParameters['orderBy'][] = $field;
$this->queryBuilderParameters['orderByDirection'][] = $direction;

return $this;
}

/**
* @deprecated Utiliser setFormTypeOption('choices', $choices) avec $choices issu d'un Store.
*/
public function initQueryBuilder(): self
{
$param = $this->queryBuilderParameters;
$this->setFormTypeOption(
'query_builder',
function (EntityRepository $er) use ($param) {
$qb = $er->createQueryBuilder('e');

if (isset($param['status'])) {
$qb->andWhere('e.status = :status')->setParameter('status', $param['status']);
}

if (isset($param['orderBy'])) {
foreach ($param['orderBy'] as $i => $field) {
$qb->addOrderBy('e.' . $param['orderBy'][$i], $param['orderByDirection'][$i]);
}
}

if (isset($param['leftJoin'])) {
foreach ($param['leftJoin'] as $i => $entityName) {
$qb->leftJoin('e.' . $entityName, $entityName)->addSelect($entityName);
}
}

if (isset($param['andWhere'])) {
foreach ($param['andWhere'] as $i => $whereClause) {
$qb->andWhere($whereClause['whereClause'])->setParameter($whereClause['key'], $whereClause['value']);
}
}

return $qb;
}
);
return $this;
}

public function autocomplete(): self
{
$this->setCustomOption(self::OPTION_AUTOCOMPLETE, true);

return $this;
}

public function renderAsNativeWidget(bool $asNative = true): self
{
$this->setCustomOption(self::OPTION_WIDGET, $asNative ? self::WIDGET_NATIVE : self::WIDGET_AUTOCOMPLETE);

return $this;
}

public function setCrudController(string $crudControllerFqcn): self
{
$this->setCustomOption(self::OPTION_CRUD_CONTROLLER, $crudControllerFqcn);

return $this;
}
}

+ 70
- 0
Form/Common/CookieConsentTypeExtension.php ファイルの表示

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

namespace Lc\SovBundle\Form\Common;

use ConnectHolland\CookieConsentBundle\Cookie\CookieChecker;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use ConnectHolland\CookieConsentBundle\Form\CookieConsentType as BaseCookieConsentType;

class CookieConsentTypeExtension extends AbstractTypeExtension
{
/**
* @var CookieChecker
*/
protected $cookieChecker;

/**
* @var array
*/
protected $cookieCategories;

/**
* @var bool
*/
protected $cookieConsentSimplified;

public function __construct(
CookieChecker $cookieChecker,
array $cookieCategories = [],
bool $cookieConsentSimplified = null
) {
$this->cookieChecker = $cookieChecker;
$this->cookieCategories = $cookieCategories;
$this->cookieConsentSimplified = $cookieConsentSimplified;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
foreach ($this->cookieCategories as $category) {
$builder->remove($category);

$data = 'true';
if ($this->cookieChecker->isCookieConsentSavedByUser() && !$this->cookieChecker->isCategoryAllowedByUser(
$category
)) {
$data = 'false';
}

$builder->add(
$category,
ChoiceType::class,
[
'expanded' => true,
'multiple' => false,
'data' => $data,
'choices' => [
['ch_cookie_consent.yes' => 'true'],
['ch_cookie_consent.no' => 'false'],
],
]
);
}
}

public static function getExtendedTypes(): iterable
{
return [BaseCookieConsentType::class];
}
}

+ 0
- 1
Form/Common/FileManagerType.php ファイルの表示

@@ -22,7 +22,6 @@ class FileManagerType extends AbstractType implements DataTransformerInterface
$this->em = $entityManager;
}


public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('path', HiddenType::class, array(

+ 258
- 0
Form/Common/FileUploadType.php ファイルの表示

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

namespace Lc\SovBundle\Form\Common;

use EasyCorp\Bundle\EasyAdminBundle\Form\DataTransformer\StringToFileTransformer;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Model\FileUploadState;
use Lc\SovBundle\Model\File\FileInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\File;
use Lc\SovBundle\Doctrine\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\String\Slugger\AsciiSlugger;
use Symfony\Component\Uid\Ulid;
use Symfony\Component\Uid\Uuid;

class FileUploadType extends AbstractType implements DataMapperInterface, DataTransformerInterface
{
protected string $projectDir;
protected EntityManager $entityManager;

public function __construct(EntityManager $entityManager, ParameterBagInterface $parameterBag)
{
$this->projectDir = $parameterBag->get('kernel.project_dir');
$this->entityManager = $entityManager;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$uploadDir = $options['upload_dir'];
$uploadFilename = $options['upload_filename'];
$uploadValidate = $options['upload_validate'];
$allowAdd = $options['allow_add'];
unset($options['upload_dir'], $options['upload_new'], $options['upload_delete'], $options['upload_filename'], $options['upload_validate'], $options['download_path'], $options['allow_add'], $options['allow_delete'], $options['compound']);

$builder->add('path', FileType::class, $options);
$builder->add('legend', TextType::class, array(
'attr' => [
"placeholder" => 'Légende'
],
'label' => false
));
$builder->add('delete', CheckboxType::class, ['required' => false, 'mapped' => false]);

$builder->setDataMapper($this);
$builder->setAttribute('state', new FileUploadState($allowAdd));
$builder->addModelTransformer(new StringToFileTransformer($uploadDir, $uploadFilename, $uploadValidate, $options['multiple']));

/*
$builder->add('path', FileType::class, array(
'block_prefix' => 'file_manager_image',
'label' => false
));

$builder->add('legend', TextType::class, array(
'block_prefix' => 'file_upload_legend',
'attr' => array(
"placeholder" => 'Légende'
),
'label' => false
));

$builder->add('position', HiddenType::class, array(
'block_prefix' => 'file_upload_position',
'empty_data' => 0,
'required' => true,
'attr' => array(
'class' => 'field-position'
),
'label' => false
));
*/
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$uploadNew = static function (UploadedFile $file, string $uploadDir, string $fileName) {
$file->move($uploadDir, $fileName);
};

$uploadDelete = static function (File $file) {
unlink($file->getPathname());
};

$uploadFilename = static function (UploadedFile $file): string {
return $file->getClientOriginalName();
};

$uploadValidate = static function (string $filename): string {
if (!file_exists($filename)) {
return $filename;
}

$index = 1;
$pathInfo = pathinfo($filename);
while (file_exists($filename = sprintf('%s/%s_%d.%s', $pathInfo['dirname'], $pathInfo['filename'], $index, $pathInfo['extension']))) {
++$index;
}

return $filename;
};

$downloadPath = function (Options $options) {
return mb_substr($options['upload_dir'], mb_strlen($this->projectDir.'/public/'));
};

$allowAdd = static function (Options $options) {
return $options['multiple'];
};

$dataClass = static function (Options $options) {
return $options['multiple'] ? null : File::class;
};

$emptyData = static function (Options $options) {
return $options['multiple'] ? [] : null;
};

$resolver->setDefaults([
'upload_dir' => $this->projectDir.'/public/uploads/files/',
'upload_new' => $uploadNew,
'upload_delete' => $uploadDelete,
'upload_filename' => $uploadFilename,
'upload_validate' => $uploadValidate,
'download_path' => $downloadPath,
'allow_add' => $allowAdd,
'allow_delete' => true,
//'data_class' => $dataClass,
'data_class' => $this->entityManager->getEntityName(FileInterface::class),
'empty_data' => $emptyData,
'multiple' => false,
'required' => false,
'error_bubbling' => false,
'allow_file_upload' => true,
]);

$resolver->setAllowedTypes('upload_dir', 'string');
$resolver->setAllowedTypes('upload_new', 'callable');
$resolver->setAllowedTypes('upload_delete', 'callable');
$resolver->setAllowedTypes('upload_filename', ['string', 'callable']);
$resolver->setAllowedTypes('upload_validate', 'callable');
$resolver->setAllowedTypes('download_path', ['null', 'string']);
$resolver->setAllowedTypes('allow_add', 'bool');
$resolver->setAllowedTypes('allow_delete', 'bool');

$resolver->setNormalizer('upload_dir', function (Options $options, string $value): string {
if (\DIRECTORY_SEPARATOR !== mb_substr($value, -1)) {
$value .= \DIRECTORY_SEPARATOR;
}

if (0 !== mb_strpos($value, $this->projectDir)) {
$value = $this->projectDir.'/'.$value;
}

if ('' !== $value && (!is_dir($value) || !is_writable($value))) {
throw new InvalidArgumentException(sprintf('Invalid upload directory "%s" it does not exist or is not writable.', $value));
}

return $value;
});
$resolver->setNormalizer('upload_filename', static function (Options $options, $fileNamePatternOrCallable) {
if (\is_callable($fileNamePatternOrCallable)) {
return $fileNamePatternOrCallable;
}

return static function (UploadedFile $file) use ($fileNamePatternOrCallable) {
return strtr($fileNamePatternOrCallable, [
'[contenthash]' => sha1_file($file->getRealPath()),
'[day]' => date('d'),
'[extension]' => $file->guessClientExtension(),
'[month]' => date('m'),
'[name]' => pathinfo($file->getClientOriginalName(), \PATHINFO_FILENAME),
'[randomhash]' => bin2hex(random_bytes(20)),
'[slug]' => (new AsciiSlugger())
->slug(pathinfo($file->getClientOriginalName(), \PATHINFO_FILENAME))
->lower()
->toString(),
'[timestamp]' => time(),
'[uuid]' => Uuid::v4()->toRfc4122(),
'[ulid]' => new Ulid(),
'[year]' => date('Y'),
]);
};
});
$resolver->setNormalizer('allow_add', static function (Options $options, string $value): bool {
if ($value && !$options['multiple']) {
throw new InvalidArgumentException('Setting "allow_add" option to "true" when "multiple" option is "false" is not supported.');
}

return $value;
});
}

/**
* {@inheritdoc}
*/
public function mapDataToForms($currentFiles, $forms): void
{
/** @var FormInterface $fileForm */
$fileForm = current(iterator_to_array($forms));
$fileForm->setData($currentFiles);
}

/**
* {@inheritdoc}
*/
public function mapFormsToData($forms, &$currentFiles): void
{
/** @var FormInterface[] $children */
$children = iterator_to_array($forms);
$uploadedFiles = $children['path']->getData();

/** @var FileUploadState $state */
$state = $children['path']->getParent()->getConfig()->getAttribute('state');
$state->setCurrentFiles($currentFiles);
$state->setUploadedFiles($uploadedFiles);
$state->setDelete($children['delete']->getData());

if (!$state->isModified()) {
return;
}

if ($state->isAddAllowed() && !$state->isDelete()) {
$currentFiles = array_merge($currentFiles, $uploadedFiles);
} else {
$currentFiles = $uploadedFiles;
}
}

/**
* {@inheritdoc}
*/
public function transform($data)
{
return $data;
}

/**
* {@inheritdoc}
*/
public function reverseTransform($data)
{
return null === $data ? '' : $data;
}
}

+ 15
- 3
Form/Setting/BaseSettingType.php ファイルの表示

@@ -5,6 +5,7 @@ namespace Lc\SovBundle\Form\Setting;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface;
use Lc\SovBundle\Form\Common\FileManagerType;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
@@ -17,13 +18,16 @@ abstract class BaseSettingType extends AbstractType
{
protected EntityManagerInterface $em;
protected SiteSettingDefinitionInterface $settingDefinition;
protected TranslatorAdmin $translatorAdmin;

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

public function buildFormSetting($label, $form, $settingDefinition, $settingEntity)
@@ -37,7 +41,8 @@ abstract class BaseSettingType extends AbstractType
'text',
TextType::class,
[
'label' => $label
'label' => $label,
'translation_domain' => 'admin',
]
);
} elseif ($settingType == 'textarea') {
@@ -45,7 +50,8 @@ abstract class BaseSettingType extends AbstractType
'text',
TextareaType::class,
[
'label' => $label
'label' => $label,
'translation_domain' => 'admin',
]
);
} elseif ($settingType == 'textarea_advanced') {
@@ -54,6 +60,7 @@ abstract class BaseSettingType extends AbstractType
CKEditorType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'attr' => [
'class' => 'field-text_editor'
]
@@ -65,6 +72,7 @@ abstract class BaseSettingType extends AbstractType
ChoiceType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'expanded' => false,
'multiple' => false,
'placeholder' => false,
@@ -77,6 +85,7 @@ abstract class BaseSettingType extends AbstractType
ChoiceType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'expanded' => true,
'multiple' => false,
'placeholder' => false,
@@ -89,6 +98,7 @@ abstract class BaseSettingType extends AbstractType
DateType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'widget' => 'single_text',
]
);
@@ -98,6 +108,7 @@ abstract class BaseSettingType extends AbstractType
TimeType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'input' => 'datetime',
'widget' => 'single_text',
]
@@ -108,6 +119,7 @@ abstract class BaseSettingType extends AbstractType
FileManagerType::class,
[
'label' => $label,
'translation_domain' => 'admin',
'attr' => [
'type' => $settingType
]

+ 65
- 0
Form/User/ConfirmDeleteUserFormType.php ファイルの表示

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

namespace Lc\SovBundle\Form\User;


use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Translation\TranslatorAdmin;
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\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ConfirmDeleteUserFormType extends AbstractType
{

protected $em;
protected $translatorAdmin;

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

/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{

$builder->add(
'confirmDelete',
CheckboxType::class,
[
'translation_domain' => 'admin',
]
);

$builder->add(
'delete',
SubmitType::class,
array(
'label'=> 'action.delete'
)

);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
// enable/disable CSRF protection for this form
'csrf_protection' => true,
// the name of the hidden HTML field that stores the token
'csrf_field_name' => '_token',
// an arbitrary string used to generate the value of the token
// using a different string for each form improves its security
'csrf_token_id' => 'ea-delete',
'translation_domain'=> 'admin'
]);
}


}

+ 32
- 0
Generator/PdfGenerator.php ファイルの表示

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

namespace Lc\SovBundle\Generator;

use Dompdf\Dompdf;
use Dompdf\Options;
use Twig\Environment;

class PdfGenerator
{
protected Environment $templating;

public function __construct(Environment $templating)
{
$this->templating = $templating;
}

public function render($filename, $view, $viewParams)
{
$pdfOptions = new Options();
$pdfOptions->set('defaultFont', 'Arial');
$dompdf = new Dompdf($pdfOptions);
$html = $this->templating->render($view, $viewParams);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$dompdf->stream($filename, [
"Attachment" => true
]);
die();
}
}

+ 4
- 4
LcSovBundle.php ファイルの表示

@@ -8,8 +8,8 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;

class LcSovBundle extends Bundle
{
public function getContainerExtension()
{
return new LcSovExtension();
}
public function getContainerExtension()
{
return new LcSovExtension();
}
}

+ 48
- 2
Model/File/FileInterface.php ファイルの表示

@@ -2,8 +2,54 @@

namespace Lc\SovBundle\Model\File;

use Lc\SovBundle\Model\User\UserInterface;

interface FileInterface
{
public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy): FileInterface;

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy): FileInterface;

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias): FileInterface;

public function getPath(): ?string;

public function setPath(?string $path): FileInterface;

public function getLegend(): ?string;

public function setLegend(?string $legend): FileInterface;

/**
* @return float
*/
public function getPosition(): float;

/**
* @param float $position
* @return $this
*/
public function setPosition(float $position): FileInterface;

public function clearPosition(): FileInterface;

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt): FileInterface;

public function getUpdatedAt(): ?\DateTimeInterface;

public function setUpdatedAt(\DateTimeInterface $updatedAt): FileInterface;

public function setTranslatableLocale($locale);

public function getLocalesEnabled(): ?array;

}
public function setLocalesEnabled(?array $localesEnabled): FileInterface;
}

+ 77
- 1
Model/Newsletter/NewsletterInterface.php ファイルの表示

@@ -1,8 +1,84 @@
<?php

namespace Lc\SovBundle\Model\Newsletter ;
namespace Lc\SovBundle\Model\Newsletter;


use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Model\User\UserInterface;

interface NewsletterInterface
{
public function getTitle(): ?string;

public function setTitle(string $title);

public function getDescription(): ?string;

public function setDescription(?string $description);

public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

/**
* @return Collection|UserInterface[]
*/
public function getUsers(): Collection;

public function addUser(UserInterface $user): NewsletterInterface;

public function removeUser(UserInterface $user): NewsletterInterface;

public function getIsMain(): ?bool;

public function setIsMain(?bool $isMain): NewsletterInterface;

public function getMetaTitle(): ?string;

public function setMetaTitle(?string $metaTitle);

public function getMetaDescription(): ?string;

public function setMetaDescription(?string $metaDescription);

public function setOldUrls($oldUrls);

public function getOldUrls(): ?array;

public function getSlug(): ?string;

public function setSlug(?string $slug);

/**
* @return float
*/
public function getPosition(): float;

/**
* @param float $position
* @return $this
*/
public function setPosition(float $position);

public function clearPosition();

public function getStatus(): ?float;

public function setStatus(float $status);

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 61
- 1
Model/Reminder/ReminderInterface.php ファイルの表示

@@ -2,6 +2,66 @@

namespace Lc\SovBundle\Model\Reminder;


use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Model\User\UserInterface;

interface ReminderInterface
{
}
public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getTitle(): ?string;

public function setTitle(string $title): ReminderInterface;

public function getDescription(): ?string;

public function setDescription(?string $description): ReminderInterface;

public function getCrudAction(): ?string;

public function setCrudAction(?string $crudAction): ReminderInterface;

public function getCrudControllerFqcn(): ?string;

public function setCrudControllerFqcn(?string $crudControllerFqcn): ReminderInterface;

public function getEntityId(): ?int;

public function setEntityId(?int $entityId): ReminderInterface;

/**
* @return Collection|UserInterface[]
*/
public function getUsers(): Collection;

public function addUser(UserInterface $user): ReminderInterface;

public function removeUser(UserInterface $user): ReminderInterface;

public function getDateReminder(): ?\DateTimeInterface;

public function setDateReminder(?\DateTimeInterface $dateReminder): ReminderInterface;

public function getDone(): ?bool;

public function setDone(?bool $done): ReminderInterface;

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 17
- 0
Model/Setting/SettingInterface.php ファイルの表示

@@ -2,7 +2,24 @@

namespace Lc\SovBundle\Model\Setting;


use Lc\SovBundle\Model\File\FileInterface;

interface SettingInterface
{
public function getName(): ?string;

public function setName(?string $name): SettingInterface;

public function getText(): ?string;

public function setText($text): SettingInterface;

public function getDate(): ?\DateTimeInterface;

public function setDate(?\DateTimeInterface $date): SettingInterface;

public function getFile(): ?FileInterface;

public function setFile(?FileInterface $file): SettingInterface;
}

+ 22
- 0
Model/Setting/SiteSettingInterface.php ファイルの表示

@@ -2,7 +2,29 @@

namespace Lc\SovBundle\Model\Setting;


use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Model\Site\SiteInterface;

interface SiteSettingInterface
{
public function getName(): ?string;

public function setName(?string $name);

public function getText(): ?string;

public function setText($text);

public function getDate(): ?\DateTimeInterface;

public function setDate(?\DateTimeInterface $date);

public function getFile(): ?FileInterface;

public function setFile(?FileInterface $file);

public function getSite(): ?SiteInterface;

public function setSite(?SiteInterface $site): SiteSettingInterface;
}

+ 93
- 2
Model/Site/NewsInterface.php ファイルの表示

@@ -1,8 +1,99 @@
<?php

namespace Lc\SovBundle\Model\Site ;
namespace Lc\SovBundle\Model\Site;

use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
use Lc\SovBundle\Model\File\FileInterface;
use Lc\SovBundle\Model\File\FileModel;
use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
use Lc\SovBundle\Model\User\UserInterface;

interface NewsInterface
{
public function getTitle(): ?string;

public function setTitle(string $title);

public function getDescription(): ?string;

public function setDescription(?string $description);

public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getDate(): ?\DateTimeInterface;

public function setDate(\DateTimeInterface $date): NewsInterface;

public function getIsSent(): ?bool;

public function setIsSent(?bool $isSent): NewsInterface;

public function getImage(): ?FileInterface;

public function setImage(?FileInterface $image): NewsInterface;

public function getNewsletter(): ?NewsletterInterface;

public function setNewsletter(?NewsletterInterface $newsletter): NewsInterface;

public function getOpenGraphTitle(): ?string;

public function setOpenGraphTitle(string $openGraphTitle): OpenGraphInterface;

public function getOpenGraphDescription(): ?string;

public function setOpenGraphDescription(?string $openGraphDescription): OpenGraphInterface;

public function getOpenGraphImage(): ?FileInterface;

public function setOpenGraphImage(?FileInterface $openGraphImage): OpenGraphInterface;

public function setMetaTitle(?string $metaTitle);

public function getMetaDescription(): ?string;

public function setMetaDescription(?string $metaDescription);

public function setOldUrls($oldUrls);

public function getOldUrls(): ?array;

public function getSlug(): ?string;

public function setSlug(?string $slug);

/**
* @return float
*/
public function getPosition(): float;

/**
* @param float $position
* @return $this
*/
public function setPosition(float $position);

public function clearPosition();

public function getStatus(): ?float;

public function setStatus(float $status);

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

}
public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 1
- 3
Model/Site/NewsModel.php ファイルの表示

@@ -13,10 +13,8 @@ use Lc\SovBundle\Model\Newsletter\NewsletterInterface;
/**
* @ORM\MappedSuperclass()
*/
abstract class NewsModel extends AbstractFullEntity implements NewsInterface, OpenGraphInterface
abstract class NewsModel extends AbstractFullEntity implements NewsInterface
{
use OpenGraphTrait;

/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="create")

+ 64
- 1
Model/Site/PageInterface.php ファイルの表示

@@ -2,7 +2,70 @@

namespace Lc\SovBundle\Model\Site;


use Lc\SovBundle\Model\User\UserInterface;


interface PageInterface
{
public function getTitle(): ?string;

public function setTitle(string $title);

public function getDescription(): ?string;

public function setDescription(?string $description);

public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getMetaTitle(): ?string;

public function setMetaTitle(?string $metaTitle);

public function getMetaDescription(): ?string;

public function setMetaDescription(?string $metaDescription);

public function setOldUrls($oldUrls);

public function getOldUrls(): ?array;

public function getSlug(): ?string;

public function setSlug(?string $slug);

/**
* @return float
*/
public function getPosition(): float;

/**
* @param float $position
* @return $this
*/
public function setPosition(float $position);

public function clearPosition();

public function getStatus(): ?float;

public function setStatus(float $status);

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

}
public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 15
- 2
Model/Site/SiteInterface.php ファイルの表示

@@ -2,8 +2,21 @@

namespace Lc\SovBundle\Model\Site;

use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Model\Setting\SiteSettingInterface;

interface SiteInterface
{
public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias): SiteInterface;

/**
* @return Collection|SiteSettingInterface[]
*/
public function getSettings(): Collection;

public function addSetting(SiteSettingInterface $setting): SiteInterface;

}
public function removeSetting(SiteSettingInterface $setting): SiteInterface;
}

+ 68
- 1
Model/Ticket/TicketInterface.php ファイルの表示

@@ -2,7 +2,74 @@

namespace Lc\SovBundle\Model\Ticket;


use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Model\User\UserInterface;

interface TicketInterface
{
public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getType(): ?string;

public function setType(string $type): TicketInterface;

public function getStatus(): ?string;

public function setStatus(string $status);

public function getSubject(): ?string;

public function setSubject(string $subject): TicketInterface;

public function getTags(): ?array;

public function setTags(?array $tags): TicketInterface;

public function getVisitorFirstname(): ?string;

public function setVisitorFirstname(?string $visitorFirstname): TicketInterface;

public function getVisitorLastname(): ?string;

public function setVisitorLastname(?string $visitorLastname): TicketInterface;

public function getVisitorEmail(): ?string;

public function setVisitorEmail(?string $visitorEmail): TicketInterface;

public function getVisitorToken(): ?string;

public function setVisitorToken(?string $visitorToken): TicketInterface;

/**
* @return Collection|TicketMessageInterface[]
*/
public function getTicketMessages(): Collection;

public function addTicketMessage(TicketMessageInterface $ticketMessage): TicketInterface;

public function removeTicketMessage(TicketMessageInterface $ticketMessage): TicketInterface;

public function getUser(): ?UserInterface;

public function setUser(?UserInterface $user): TicketInterface;

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

}
public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 42
- 1
Model/Ticket/TicketMessageInterface.php ファイルの表示

@@ -2,7 +2,48 @@

namespace Lc\SovBundle\Model\Ticket;


use Lc\SovBundle\Model\User\UserInterface;

interface TicketMessageInterface
{
public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getStatus(): ?float;

public function setStatus(float $status): TicketMessageInterface;

public function getMessage(): ?string;

public function setMessage(string $message): TicketMessageInterface;

public function getTicket(): TicketInterface;

public function setTicket(TicketInterface $ticket): TicketMessageInterface;

public function getAnswerByAdmin(): ?bool;

public function setAnswerByAdmin(?bool $answerByAdmin): TicketMessageInterface;

public function getImageFilename(): ?string;

public function setImageFilename(?string $imageFilename): TicketMessageInterface;

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

}
public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 2
- 1
Model/Ticket/TicketModel.php ファイルの表示

@@ -66,7 +66,7 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
protected $visitorToken;

/**
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketMessageInterface", mappedBy="ticket", orphanRemoval=true, cascade={"persist", "remove"})
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketMessageInterface", mappedBy="ticket",cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"id" = "ASC"})
*/
protected $ticketMessages;
@@ -76,6 +76,7 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
*/
protected $user;


public function __construct()
{
$this->ticketMessages = new ArrayCollection();

+ 72
- 1
Model/User/GroupUserInterface.php ファイルの表示

@@ -2,7 +2,78 @@

namespace Lc\SovBundle\Model\User;


use Doctrine\Common\Collections\Collection;

interface GroupUserInterface
{
public function getDescription(): ?string;

public function setDescription(?string $description);

public function getCreatedBy(): ?UserInterface;

public function setCreatedBy(?UserInterface $createdBy);

public function getUpdatedBy(): ?UserInterface;

public function setUpdatedBy(?UserInterface $updatedBy);

public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias);

public function getTitle(): ?string;

public function setTitle(string $title);

public function addUser(UserInterface $user): GroupUserInterface;

/**
* @return Collection|UserInterface[]
*/
public function getUsers(): Collection;

public function removeUser(UserInterface $user): GroupUserInterface;

public function getMetaTitle(): ?string;

public function setMetaTitle(?string $metaTitle);

public function getMetaDescription(): ?string;

public function setMetaDescription(?string $metaDescription);

public function setOldUrls($oldUrls);

public function getOldUrls(): ?array;

public function getSlug(): ?string;

public function setSlug(?string $slug);

/**
* @return float
*/
public function getPosition(): float;

/**
* @param float $position
* @return $this
*/
public function setPosition(float $position);

public function clearPosition();

public function getStatus(): ?float;

public function setStatus(float $status);

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt);

public function getUpdatedAt(): ?\DateTimeInterface;

}
public function setUpdatedAt(\DateTimeInterface $updatedAt);
}

+ 101
- 1
Model/User/UserInterface.php ファイルの表示

@@ -2,7 +2,107 @@

namespace Lc\SovBundle\Model\User;


use Doctrine\Common\Collections\Collection;
use Lc\SovBundle\Model\Ticket\TicketInterface;


interface UserInterface
{
public function getDevAlias(): ?string;

public function setDevAlias(?string $devAlias): UserInterface;

public function getCreatedAt(): ?\DateTimeInterface;

public function setCreatedAt(\DateTimeInterface $createdAt): UserInterface;

public function getUpdatedAt(): ?\DateTimeInterface;

public function setUpdatedAt(\DateTimeInterface $updatedAt): UserInterface;

public function getEmail(): ?string;

public function setEmail(string $email): UserInterface;

/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUsername(): string;

public function getGender(): ?bool;

public function setGender(?bool $gender): UserInterface;

public function getBirthdate(): ?\DateTimeInterface;

public function setBirthdate(?\DateTimeInterface $birthdate): UserInterface;

/**
* @see UserInterface
*/
public function getRoles(): array;

public function setRoles(array $roles): UserInterface;

public function hasRole($role);

/**
* @see UserInterface
*/
public function getPassword(): string;

public function setPassword(string $password): UserInterface;

public function generatePassword($length = 8): string;

/**
* @see UserIn
*/
public function getSalt();

/**
* @see UserInterface
*/
public function eraseCredentials();

public function getLastname(): ?string;

public function setLastname(?string $lastname): UserInterface;

public function getFirstname(): ?string;

public function setFirstname(?string $firstname): UserInterface;

public function getPhone(): ?string;

public function setPhone(?string $phone): UserInterface;

public function isVerified(): bool;

public function setIsVerified(bool $isVerified): UserInterface;

/**
* @return Collection|GroupUserInterface[]
*/
public function getGroupUsers(): Collection;

public function addGroupUser(GroupUserInterface $groupUser): UserInterface;

public function removeGroupUser(GroupUserInterface $groupUser): UserInterface;

/**
* @return Collection|TicketInterface[]
*/
public function getTickets(): Collection;

public function addTicket(TicketInterface $ticket): UserInterface;

public function removeTicket(TicketInterface $ticket): UserInterface;

public function getTicketTypesNotification(): ?array;

}
public function setTicketTypesNotification(?array $ticketTypesNotification): UserInterface;
}

+ 18
- 2
Model/User/UserModel.php ファイルの表示

@@ -11,11 +11,12 @@ use Lc\SovBundle\Doctrine\Extension\DevAliasTrait;
use Lc\SovBundle\Doctrine\Extension\TimestampableTrait;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Lc\SovBundle\Model\User\UserInterface as SovUserInterface;

/**
* @ORM\MappedSuperclass()
*/
abstract class UserModel implements EntityInterface, UserInterface, DevAliasInterface
abstract class UserModel implements EntityInterface, UserInterface, SovUserInterface, DevAliasInterface
{
use DevAliasTrait;
use TimestampableTrait;
@@ -72,7 +73,7 @@ abstract class UserModel implements EntityInterface, UserInterface, DevAliasInte
protected $groupUsers;

/**
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketInterface", mappedBy="user")
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketInterface", mappedBy="user", cascade={"remove"})
*/
protected $tickets;

@@ -81,6 +82,11 @@ abstract class UserModel implements EntityInterface, UserInterface, DevAliasInte
*/
protected $ticketTypesNotification = [];

/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected $lastLogin;

public function __construct()
{
$this->tickets = new ArrayCollection();
@@ -334,5 +340,15 @@ abstract class UserModel implements EntityInterface, UserInterface, DevAliasInte
return $this;
}

public function getLastLogin()
{
return $this->lastLogin;
}

public function setLastLogin(\DateTime $time = null)
{
$this->lastLogin = $time;

return $this;
}
}

+ 142
- 1
Repository/AbstractRepositoryInterface.php ファイルの表示

@@ -2,8 +2,149 @@

namespace Lc\SovBundle\Repository;

use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\LazyCriteriaCollection;
use Doctrine\ORM\NativeQuery;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\ORM\QueryBuilder;

interface AbstractRepositoryInterface
{
public function setDefaultLocale($locale);

}
public function getOneOrNullResult(QueryBuilder $qb, $locale = null, $hydrationMode = null);

public function getResult(QueryBuilder $qb, $locale = null, $hydrationMode = AbstractQuery::HYDRATE_OBJECT);

public function getArrayResult(QueryBuilder $qb, $locale = null);

public function getSingleResult(QueryBuilder $qb, $locale = null, $hydrationMode = null);

public function getScalarResult(QueryBuilder $qb, $locale = null);

public function getSingleScalarResult(QueryBuilder $qb, $locale = null);

/**
* Creates a new QueryBuilder instance that is prepopulated for this entity name.
*
* @param string $alias
* @param string $indexBy The index for the from.
*
* @return QueryBuilder
*/
public function createQueryBuilder($alias, $indexBy = null);

/**
* Creates a new result set mapping builder for this entity.
*
* The column naming strategy is "INCREMENT".
*
* @param string $alias
*
* @return ResultSetMappingBuilder
*/
public function createResultSetMappingBuilder($alias);

/**
* Creates a new Query instance based on a predefined metadata named query.
*
* @param string $queryName
*
* @return Query
* @deprecated
*
*/
public function createNamedQuery($queryName);

/**
* Creates a native SQL query.
*
* @param string $queryName
*
* @return NativeQuery
* @deprecated
*
*/
public function createNativeNamedQuery($queryName);

/**
* Clears the repository, causing all managed entities to become detached.
*
* @deprecated 2.8 This method is being removed from the ORM and won't have any replacement
*
* @return void
*/
public function clear();

/**
* Finds an entity by its primary key / identifier.
*
* @param mixed $id The identifier.
* @param int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* during the search.
* @param int|null $lockVersion The lock version.
*
* @return object|null The entity instance or NULL if the entity can not be found.
* @psalm-return ?T
*/
public function find($id, $lockMode = null, $lockVersion = null);

/**
* Finds all entities in the repository.
*
* @psalm-return list<T> The entities.
*/
public function findAll();

/**
* Finds entities by a set of criteria.
*
* @param int|null $limit
* @param int|null $offset
* @psalm-param array<string, mixed> $criteria
* @psalm-param array<string, string>|null $orderBy
*
* @psalm-return list<T> The objects.
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null);

/**
* Finds a single entity by a set of criteria.
*
* @psalm-param array<string, mixed> $criteria
* @psalm-param array<string, string>|null $orderBy
*
* @return object|null The entity instance or NULL if the entity can not be found.
* @psalm-return ?T
*/
public function findOneBy(array $criteria, ?array $orderBy = null);

/**
* Counts entities by a set of criteria.
*
* @psalm-param array<string, mixed> $criteria
*
* @return int The cardinality of the objects that match the given criteria.
*
* @todo Add this method to `ObjectRepository` interface in the next major release
*/
public function count(array $criteria);

/**
* @return string
*/
public function getClassName();

/**
* Select all elements from a selectable that match the expression and
* return a new collection containing these elements.
*
* @return LazyCriteriaCollection
* @psalm-return Collection<int, T>
*/
public function matching(Criteria $criteria);
}

+ 44
- 1
Repository/AbstractRepositoryQuery.php ファイルの表示

@@ -6,6 +6,7 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Knp\Component\Pager\PaginatorInterface;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Model\User\UserInterface;

abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
{
@@ -130,7 +131,6 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
return $this;
}*/

// @TODO : créer un addOrderBy et un orderBy
public function orderBy(string $field, string $sort = 'ASC'): self
{
if (strpos($field, '.')!==false) {
@@ -140,6 +140,12 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
}
}

public function setOrderBy(string $field, string $sort = 'ASC'): self
{
$this->resetDQLParts(['orderBy']);
return $this->orderBy($field, $sort);
}

public function filterById(int $id):self
{
return $this
@@ -147,6 +153,20 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
->setParameter('id', $id);
}

public function filterByCreatedBy(UserInterface $user):self
{
return $this
->andWhere('.createdBy = :user')
->setParameter('user', $user);
}

public function filterByUpdatedBy(UserInterface $user):self
{
return $this
->andWhere('.updatedBy = :user')
->setParameter('user', $user);
}

public function andWhereEqual($field, $value)
{
return $this->andWhere('.'.$field.' = :'.$field)->setParameter($field, $value);
@@ -222,5 +242,28 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface
{
return $this->andWhere('.status >= 0');
}

/*
* POSITION
*/

public function filterByPositionBiggerThan(int $position)
{
return $this->andWhere('.position > :position')->setParameter('position', $position);
}

public function filterByPositionSmallerThan(int $position)
{
return $this->andWhere('.position < :position')->setParameter('position', $position);
}

public function enableCache($lifetime, $idCache)
{
return $this->getQueryBuilder()->getQuery()
->useQueryCache(true)
->setQueryCacheLifetime($lifetime)
->enableResultCache($lifetime, $idCache);
}

}


+ 7
- 0
Repository/AbstractStore.php ファイルの表示

@@ -115,6 +115,13 @@ abstract class AbstractStore implements StoreInterface
return $query->find();
}

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

public function getParent(bool $isOnline = true, $query = null)
{
$query = $this->createDefaultQuery($query);

+ 50
- 0
Repository/File/FileRepositoryQueryInterface.php ファイルの表示

@@ -2,7 +2,57 @@

namespace Lc\SovBundle\Repository\File;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Lc\SovBundle\Doctrine\EntityInterface;

interface FileRepositoryQueryInterface
{
public function create();

public function call(callable $fn);

public function count();

public function findOne();

public function find(): array;

public function limit(int $maxResults);

public function paginate(int $page = 1, int $limit = 20);

public function getRepository(): ServiceEntityRepository;

public function getQueryBuilder(): QueryBuilder;

public function groupBy(string $field);

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

public function filterById(int $id);

public function andWhereEqual($field, $value);

public function filterByOldUrl(string $oldUrl);

public function resetRelationsJoin(): void;

public function filterByDevAlias(string $devAlias);

public function filterBySlug(string $slug);

public function filterIsParent();

public function filterIsChildren();

public function filterByParent(EntityInterface $parent = null);

public function filterIsOffline();

public function filterIsOnline();

public function filterIsDeleted();

public function filterIsOnlineAndOffline();
}

+ 1
- 2
Repository/File/FileStore.php ファイルの表示

@@ -13,15 +13,14 @@ class FileStore extends AbstractStore implements FileStoreInterface
{
$this->query = $query;
}

public function orderByDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
{

return $query;
}

public function filtersDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
{

return $query;
}


+ 30
- 0
Repository/File/FileStoreInterface.php ファイルの表示

@@ -2,7 +2,37 @@

namespace Lc\SovBundle\Repository\File;

use Lc\SovBundle\Repository\RepositoryQueryInterface;

interface FileStoreInterface
{
public function createDefaultQuery(RepositoryQueryInterface $query = null): RepositoryQueryInterface;

public function createQuery(RepositoryQueryInterface $query = null): RepositoryQueryInterface;

public function getRepositoryQuery();

public function getOneById(int $id);

public function getOneBySlug(string $slug, bool $isOnline = true, $query = null);

public function getOneByDevAlias(string $devAlias, $query = null);

public function getOneOnlineByDevAlias(string $devAlias, $query = null);

public function getOneByOldUrl(string $oldUrl, $query = null);

public function get($query = null);

public function getAll($query = null);

public function getOnline($query = null);

public function getParent(bool $isOnline = true, $query = null);

public function orderByDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;

public function filtersDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;

public function relationsDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;
}

+ 51
- 0
Repository/Newsletter/NewsletterRepositoryQueryInterface.php ファイルの表示

@@ -2,7 +2,58 @@

namespace Lc\SovBundle\Repository\Newsletter;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Repository\AbstractRepositoryQuery;

interface NewsletterRepositoryQueryInterface
{
public function create();

public function call(callable $fn);

public function count();

public function findOne();

public function find(): array;

public function limit(int $maxResults);

public function paginate(int $page = 1, int $limit = 20);

public function getRepository(): ServiceEntityRepository;

public function getQueryBuilder(): QueryBuilder;

public function groupBy(string $field);

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

public function filterById(int $id);

public function andWhereEqual($field, $value);

public function filterByOldUrl(string $oldUrl);

public function resetRelationsJoin(): void;

public function filterByDevAlias(string $devAlias);

public function filterBySlug(string $slug);

public function filterIsParent();

public function filterIsChildren();

public function filterByParent(EntityInterface $parent = null);

public function filterIsOffline();

public function filterIsOnline();

public function filterIsDeleted();

public function filterIsOnlineAndOffline();
}

+ 1
- 2
Repository/Newsletter/NewsletterStore.php ファイルの表示

@@ -13,15 +13,14 @@ class NewsletterStore extends AbstractStore implements NewsletterStoreInterface
{
$this->query = $query;
}

public function orderByDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
{

return $query;
}

public function filtersDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
{

return $query;
}


+ 30
- 0
Repository/Newsletter/NewsletterStoreInterface.php ファイルの表示

@@ -2,7 +2,37 @@

namespace Lc\SovBundle\Repository\Newsletter;

use Lc\SovBundle\Repository\RepositoryQueryInterface;

interface NewsletterStoreInterface
{
public function createDefaultQuery(RepositoryQueryInterface $query = null): RepositoryQueryInterface;

public function createQuery(RepositoryQueryInterface $query = null): RepositoryQueryInterface;

public function getRepositoryQuery();

public function getOneById(int $id);

public function getOneBySlug(string $slug, bool $isOnline = true, $query = null);

public function getOneByDevAlias(string $devAlias, $query = null);

public function getOneOnlineByDevAlias(string $devAlias, $query = null);

public function getOneByOldUrl(string $oldUrl, $query = null);

public function get($query = null);

public function getAll($query = null);

public function getOnline($query = null);

public function getParent(bool $isOnline = true, $query = null);

public function orderByDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;

public function filtersDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;

public function relationsDefault(RepositoryQueryInterface $query): RepositoryQueryInterface;
}

+ 76
- 1
Repository/Reminder/ReminderRepositoryQueryInterface.php ファイルの表示

@@ -2,7 +2,82 @@

namespace Lc\SovBundle\Repository\Reminder;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\AbstractRepositoryQuery;

interface ReminderRepositoryQueryInterface
{
public function create();

public function call(callable $fn);

public function count();

public function findOne();

public function find(): array;

public function limit(int $maxResults);

public function paginate(int $page = 1, int $limit = 20);

public function getRepository(): ServiceEntityRepository;

public function getQueryBuilder(): QueryBuilder;

public function groupBy(string $field);

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

public function filterById(int $id);

public function andWhereEqual($field, $value);

public function filterByOldUrl(string $oldUrl);

public function resetRelationsJoin(): void;

public function filterByDevAlias(string $devAlias);

public function filterBySlug(string $slug);

public function filterIsParent();

public function filterIsChildren();

public function filterByParent(EntityInterface $parent = null);

public function filterIsOffline();

public function filterIsOnline();

public function filterIsDeleted();

public function filterIsOnlineAndOffline();

public function filterByDone($done = false): ReminderRepositoryQueryInterface;

public function joinUser(): ReminderRepositoryQueryInterface;

public function filterByUser(UserInterface $user): ReminderRepositoryQueryInterface;

public function filterByCrudAction(?string $crudAction = null
): ReminderRepositoryQueryInterface;

public function filterByCrudControllerFqcn(?string $crudControllerFqcn = null
): ReminderRepositoryQueryInterface;

public function filterByEntityId(?int $entityId = null): ReminderRepositoryQueryInterface;

public function filterIsNotDone(): ReminderRepositoryQueryInterface;

public function filterLikeCrudAction(string $crudAction): ReminderRepositoryQueryInterface;

public function filterLikeCrudControllerFqcn(string $crudControllerFqcn
): ReminderRepositoryQueryInterface;

}
public function filterLikeEntityId(int $entityId): ReminderRepositoryQueryInterface;
}

変更されたファイルが多すぎるため、一部のファイルは表示されません

読み込み中…
キャンセル
保存