@@ -3,11 +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; | |||
@@ -27,7 +30,7 @@ class UserBuilder | |||
} | |||
public function create( string $email, string $password, array $roles=[]) | |||
public function create(string $email, string $password, array $roles = []) | |||
{ | |||
$user = $this->userFactory->create(); | |||
$user->setEmail($email); | |||
@@ -84,7 +87,8 @@ class UserBuilder | |||
} | |||
} | |||
public function setLastLogin(?UserInterface $user){ | |||
public function setLastLogin(?UserInterface $user) | |||
{ | |||
if ($user instanceof UserInterface) { | |||
$user->setLastLogin(new \DateTime()); | |||
$this->entityManager->update($user); |
@@ -70,4 +70,9 @@ class DateComponent | |||
return $hour ; | |||
} | |||
public function getTotalMinutes(\DateTimeInterface $time): int | |||
{ | |||
return (int) $time->format('H') * 60 + (int) $time->format('i'); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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 | |||
{ |
@@ -61,6 +61,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 | |||
{ | |||
@@ -813,7 +814,6 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
$filteredValue = ['value' => $context->getRequest()->query->get('q')]; | |||
$filterManager->applyFilter($repositoryQuery, $field, $filteredValue); | |||
$repositoryQuery->select('.' . $autocompleteContext['propertyName']); | |||
//dump($repositoryQuery->getQueryBuilder()->getQuery()->getDQL()); | |||
$responses = array(); | |||
foreach ($repositoryQuery->find() as $result) { | |||
@@ -840,5 +840,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; | |||
} | |||
} | |||
@@ -18,6 +18,7 @@ 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; | |||
@@ -42,64 +43,54 @@ trait ControllerTrait | |||
//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 | |||
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, | |||
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, | |||
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, | |||
] | |||
); | |||
} | |||
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 | |||
); | |||
} | |||
@@ -108,8 +99,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); | |||
@@ -138,6 +133,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); | |||
@@ -284,4 +284,4 @@ trait ControllerTrait | |||
set_time_limit(0); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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,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; | |||
} |
@@ -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; | |||
} |
@@ -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); |
@@ -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); |
@@ -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; |
@@ -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); | |||
@@ -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); | |||
@@ -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) ; |
@@ -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); |
@@ -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); | |||
@@ -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; | |||
} |
@@ -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' | |||
]); | |||
} | |||
} |
@@ -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(); |
@@ -73,7 +73,7 @@ abstract class UserModel implements EntityInterface, UserInterface, SovUserInter | |||
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; | |||
@@ -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 | |||
{ | |||
@@ -147,6 +148,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); |
@@ -21,6 +21,7 @@ title: | |||
editWithTitle: 'Modifier "%label%" : %title% (#%id%)' | |||
detail: Voir "%label%" (#%id%) | |||
un_titre: Un titre | |||
delete: "Supprimer %label% : <br /> %title% (#%id%)" | |||
account: | |||
profile: Mes informations personnelles | |||
change_password: Changer de mot de passe | |||
@@ -53,6 +54,7 @@ entity: | |||
label_plurial: Utilisateurs | |||
fields: | |||
firstname: Prénom | |||
ticketTypesNotification: Alerte par email lors de ticket de type | |||
lastname: Nom | |||
gender: Sexe | |||
genderChoices: | |||
@@ -61,6 +63,9 @@ entity: | |||
birthdate: Date de naissance | |||
groupUsers: Groupe d'utilisateurs | |||
isVerified: Actif | |||
flashes: | |||
error: | |||
cannotDelete: L'utilisateur ne peut pas être supprimé, voir les élements dans suppression impossible. | |||
Page: | |||
label: Page | |||
label_plurial: Pages | |||
@@ -102,6 +107,7 @@ entity: | |||
being-processed: En attente | |||
closed: Fermé | |||
TicketMessage: | |||
label_plurial: Message de ticket | |||
fields: | |||
message: Votre réponse | |||
closeTicket: Fermer la demande | |||
@@ -114,6 +120,7 @@ entity: | |||
default: | |||
fields: | |||
id: Id | |||
confirmDelete: Confirmer la suppression | |||
createdAt: Créé le | |||
user: Utilisateur | |||
firstname: Prénom |
@@ -0,0 +1,74 @@ | |||
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||
{# @var entities \EasyCorp\Bundle\EasyAdminBundle\Collection\EntityDtoCollection #} | |||
{# @var paginator \EasyCorp\Bundle\EasyAdminBundle\Orm\EntityPaginator #} | |||
{% extends ea.templatePath('layout') %} | |||
{% trans_default_domain ea.i18n.translationDomain %} | |||
{% block content_title %} | |||
{{ 'delete'|sov_trans_admin_title(translation_entity_name, {id: ea.getEntity().getInstance().getId(), title: ea.getEntity().getInstance()})|raw }} | |||
{% endblock %} | |||
{% block content_breadcrumb %} | |||
{{ include('@LcSov/adminlte/block/breadcrumb.html.twig') }} | |||
{% endblock content_breadcrumb %} | |||
{% block page_actions %} | |||
{% endblock page_actions %} | |||
{% block main %} | |||
{% block main_prepend %}{% endblock %} | |||
<div class="col-12" id="{% block detail_id %}{% endblock detail_id %}"> | |||
{% block card_wrapper %} | |||
<div class="card card-outline card-primary"> | |||
{% block card_header_wrapper %} | |||
<div class="card-header"> | |||
<div class="btn-list float-sm-right"> | |||
</div> | |||
</div> | |||
{% endblock %} | |||
{% block card_body_wrapper %} | |||
<div class="card-body"> | |||
{% block detail_fields %} | |||
{% for type, messageList in warning_message_list %} | |||
{% if messageList|length >0 %} | |||
<div class="alert alert-{{ type }}"> | |||
{% if type =='danger' %} | |||
<h5><i class="icon fas fa-ban"></i> Suppresion impossible</h5> | |||
{% elseif type =='warning' %} | |||
<h5><i class="icon fas fa-exclamation-triangle"></i> À vérifier avant | |||
suppression</h5> | |||
{% elseif type =='info' %} | |||
<h5><i class="icon fas fa-info"></i> Élements qui seront supprimés</h5> | |||
{% endif %} | |||
{% for message in messageList %} | |||
<p>{{ message|raw }}</p> | |||
{% endfor %} | |||
</div> | |||
{% endif %} | |||
{% endfor %} | |||
{% endblock %} | |||
</div> | |||
{% endblock %} | |||
{% block card_footer_wrapper %} | |||
<div class="card-footer"> | |||
<div class="row"> | |||
{% block delete_form %} | |||
{% form_theme confirm_delete_user_form '@LcSov/adminlte/crud/form_theme.html.twig' %} | |||
{{ form_start(confirm_delete_user_form) }} | |||
<input type="hidden" name="token" value="{{ csrf_token('ea-delete') }}"/> | |||
{{ form_end(confirm_delete_user_form) }} | |||
{% endblock delete_form %} | |||
</div> | |||
</div> | |||
{% endblock %} | |||
</div> | |||
{% endblock card_wrapper %} | |||
</div> | |||
{% block main_append %}{% endblock %} | |||
{% endblock main %} |
@@ -234,8 +234,6 @@ | |||
{% endif %} | |||
<div class="col-12"> | |||
{# {{ dump(form.vars) }} #} | |||
{# {{ dump(form.vars.ea_crud_form.ea_field) }} #} | |||
<div class="input-group"> | |||
<div class="input-group-prepend"> | |||
{% if form.parent.vars['row_attr']['data-sortable'] is defined %} |