@@ -47,6 +47,8 @@ use Lc\SovBundle\Field\CollectionField; | |||
use Lc\SovBundle\Field\Filter\FilterManager; | |||
use Lc\SovBundle\Form\Common\FiltersFormType; | |||
use Lc\SovBundle\Form\Common\PositionType; | |||
use Lc\SovBundle\Repository\EntityRepository; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\FlashBagTranslator; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||
@@ -61,6 +63,9 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
protected FormInterface $filtersForm; | |||
abstract public function getRepositoryQuery(): RepositoryQueryInterface; | |||
public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore | |||
{ | |||
if ($responseParameters->get('global_actions')) { | |||
@@ -325,49 +330,52 @@ abstract class AbstractAdminController extends EaAbstractCrudController | |||
return $this->redirect($url); | |||
} | |||
public function createIndexQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder { | |||
$queryBuilder = parent::createIndexQueryBuilder( | |||
$searchDto, | |||
$entityDto, | |||
$fields, | |||
$filters | |||
); | |||
public function createIndexRepositoryQuery( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): RepositoryQueryInterface | |||
{ | |||
$repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery($this->getRepositoryQuery(), $searchDto, $entityDto, $fields, $filters); | |||
//TOdo utiliser les repositoryQuery ? | |||
// TODO : déplacer dans EntotyRepository | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$entityId = $searchDto->getRequest()->get('entityId'); | |||
if ($entityId !== null) { | |||
$queryBuilder->andWhereParent('entity', $entityId); | |||
if ($entityDto->getInstance()) { | |||
$repositoryQuery->filterByParent($entityDto->getInstance()); | |||
} else { | |||
$queryBuilder->andWhereParentIsNull('entity'); | |||
$repositoryQuery->filterIsParent(); | |||
} | |||
} | |||
$this->filtersForm = $this->createForm( | |||
FiltersFormType::class, | |||
null, | |||
array( | |||
'fields' => $fields, | |||
'entity_dto' => $entityDto, | |||
'entity_class' => $this->getEntityFqcn(), | |||
'entity_name' => $entityDto->getName(), | |||
) | |||
FiltersFormType::class, | |||
null, | |||
array( | |||
'fields' => $fields, | |||
'entity_dto' => $entityDto, | |||
'entity_class' => $this->getEntityFqcn(), | |||
'entity_name' => $entityDto->getName(), | |||
) | |||
); | |||
$filterManager = $this->get(FilterManager::class); | |||
$this->filtersForm->handleRequest($searchDto->getRequest()); | |||
$filterManager->handleFiltersForm($queryBuilder, $this->filtersForm, $fields, $entityDto); | |||
$filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto); | |||
return $repositoryQuery; | |||
} | |||
public function createIndexQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder { | |||
return $queryBuilder; | |||
$repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters); | |||
return $repositoryQuery->getQueryBuilder(); | |||
} | |||
public function createSortQueryBuilder( |
@@ -18,6 +18,7 @@ use Lc\SovBundle\Container\Ticket\TicketMessageContainer; | |||
use Lc\SovBundle\Container\User\GroupUserContainer; | |||
use Lc\SovBundle\Container\User\UserContainer; | |||
use Lc\SovBundle\Field\Filter\FilterManager; | |||
use Lc\SovBundle\Repository\EntityRepository; | |||
use Lc\SovBundle\Solver\Setting\SettingSolver; | |||
use Lc\SovBundle\Translation\FlashBagTranslator; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
@@ -36,53 +37,55 @@ trait ControllerTrait | |||
public static function getSubscribedServices() | |||
{ | |||
return array_merge( | |||
parent::getSubscribedServices(), | |||
[ | |||
Environment::class => Environment::class, | |||
Security::class => Security::class, | |||
EntityManagerInterface::class => EntityManagerInterface::class, | |||
UrlGeneratorInterface::class => UrlGeneratorInterface::class, | |||
SessionInterface::class => SessionInterface::class, | |||
PaginatorInterface::class => PaginatorInterface::class, | |||
RequestStack::class => RequestStack::class, | |||
EventDispatcherInterface::class => EventDispatcherInterface::class, | |||
LoggerInterface::class => LoggerInterface::class, | |||
TranslatorInterface::class => TranslatorInterface::class, | |||
TranslatorAdmin::class => TranslatorAdmin::class, | |||
FilterManager::class => FilterManager::class, | |||
FlashBagTranslator::class => FlashBagTranslator::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, | |||
] | |||
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, | |||
TranslatorInterface::class => TranslatorInterface::class, | |||
TranslatorAdmin::class => TranslatorAdmin::class, | |||
FilterManager::class => FilterManager::class, | |||
FlashBagTranslator::class => FlashBagTranslator::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, | |||
] | |||
); | |||
} | |||
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 | |||
); | |||
} | |||
@@ -91,7 +94,7 @@ 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) { | |||
@@ -103,8 +106,8 @@ trait ControllerTrait | |||
if ($entityId) { | |||
$adminUrlGenerator->setEntityId($entityId); | |||
} | |||
if($extraParam){ | |||
foreach ($extraParam as $key=>$value) { | |||
if ($extraParam) { | |||
foreach ($extraParam as $key => $value) { | |||
$adminUrlGenerator->set($key, $value); | |||
} | |||
} |
@@ -10,9 +10,14 @@ use Lc\SovBundle\Factory\Newsletter\NewsletterFactory; | |||
use Lc\SovBundle\Field\BooleanField; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
abstract class NewsletterAdminController extends AbstractAdminController | |||
{ | |||
public function getRepositoryQuery() :RepositoryQueryInterface | |||
{ | |||
return $this->get(NewsletterContainer::class)->getRepositoryQuery(); | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return array_merge( |
@@ -11,10 +11,16 @@ use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\Site\NewsFactory; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
abstract class NewsAdminController extends AbstractAdminController | |||
{ | |||
public function getRepositoryQuery() :RepositoryQueryInterface | |||
{ | |||
return $this->get(NewsContainer::class)->getRepositoryQuery(); | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$panel = parent::configureFields($pageName); |
@@ -10,10 +10,16 @@ use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\Site\PageFactory; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
abstract class PageAdminController extends AbstractAdminController | |||
{ | |||
public function getRepositoryQuery() :RepositoryQueryInterface | |||
{ | |||
return $this->get(PageContainer::class)->getRepositoryQuery(); | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$panel = parent::configureFields($pageName); |
@@ -27,16 +27,17 @@ use Lc\SovBundle\Form\Ticket\TicketStatusType; | |||
use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
class TicketAdminController extends AbstractAdminController | |||
abstract class TicketAdminController extends AbstractAdminController | |||
{ | |||
public static function getEntityFqcn(): string | |||
public function getRepositoryQuery() :RepositoryQueryInterface | |||
{ | |||
return TicketInterface::class; | |||
return $this->getTicketContainer()->getRepositoryQuery(); | |||
} | |||
public function createEntity(string $entityFqcn) | |||
@@ -61,10 +62,10 @@ class TicketAdminController extends AbstractAdminController | |||
->hideOnForm(), | |||
DateField::new('createdAt')->setFormat('short') | |||
->hideOnForm(), | |||
TextField::new('visitorFirstName') | |||
TextField::new('visitorFirstname') | |||
->setTemplatePath('@LcSov/admin/ticket/field/firstname.html.twig') | |||
->hideOnForm(), | |||
TextField::new('visitorLastName') | |||
TextField::new('visitorLastname') | |||
->setTemplatePath('@LcSov/admin/ticket/field/lastname.html.twig') | |||
->hideOnForm(), | |||
TextField::new('visitorEmail') |
@@ -7,9 +7,14 @@ use Lc\SovBundle\Container\User\GroupUserContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\User\GroupUserFactory; | |||
use Lc\SovBundle\Field\StatusField; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
abstract class GroupUserAdminController extends AbstractAdminController | |||
{ | |||
public function getRepositoryQuery(): RepositoryQueryInterface | |||
{ | |||
return $this->get(GroupUserContainer::class)->getRepositoryQuery(); | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ |
@@ -5,7 +5,9 @@ namespace Lc\SovBundle\Doctrine; | |||
use Doctrine\ORM\Decorator\EntityManagerDecorator; | |||
use Doctrine\ORM\EntityManager as DoctrineEntityManager; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Knp\Component\Pager\PaginatorInterface; | |||
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |||
/** |
@@ -3,8 +3,8 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\EntityRepository; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -20,6 +20,13 @@ class AssociationFilter | |||
{ | |||
$targetEntity = $options['entity_dto']->getPropertyMetadata($fieldDto->getProperty())->get('targetEntity'); | |||
if($fieldDto->getCustomOption('choices')){ | |||
$choices = $fieldDto->getCustomOption('choices'); | |||
}else if($fieldDto->getFormTypeOption('choices') !=null){ | |||
$choices = $fieldDto->getFormTypeOption('choices'); | |||
}else{ | |||
$choices = array(); | |||
} | |||
//todo utiliser choices plutot que query_builder voir ProductCategoriesFilter | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
@@ -27,9 +34,7 @@ class AssociationFilter | |||
array( | |||
'class' => $targetEntity, | |||
'placeholder' => '--', | |||
'query_builder' => function (EntityRepository $repo){ | |||
return $repo->createQueryBuilder('entity'); | |||
}, | |||
'choices' => $choices, | |||
'required' => false, | |||
'attr' => array( | |||
'class' => 'select2 input-sm', | |||
@@ -41,24 +46,19 @@ class AssociationFilter | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, $filteredValue = null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$queryBuilder->andWhere('entity.'.$fieldProperty.' = :'.$fieldProperty.''); | |||
$queryBuilder->setParameter($fieldProperty, $filteredValue); | |||
$repositoryQuery->andWhere('.'.$fieldProperty.' = :'.$fieldProperty.''); | |||
$repositoryQuery->setParameter($fieldProperty, $filteredValue); | |||
/* //TODO Faut généraliser avec TreeInterface, ça ne doit pas être ici | |||
if ($field['property'] == 'productCategories') { | |||
$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ' OR product_categories.parent = :' . $field['property']); | |||
$queryBuilder->setParameter($field['property'], $filter); | |||
if ($field['type_options']['multiple']) { | |||
$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ''); | |||
$repositoryQuery->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ''); | |||
} else { | |||
} | |||
if ($filter instanceof TreeInterface && $filter->getParent() == null) { | |||
$queryBuilder->setParameter($field['property'], array_merge(array($filter), $filter->getChildrens()->toArray())); | |||
$repositoryQuery->setParameter($field['property'], array_merge(array($filter), $filter->getChildrens()->toArray())); | |||
} else { | |||
}*/ | |||
} |
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -34,26 +35,26 @@ class CheckboxFilter | |||
)); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, string $filteredValue= null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty.' = :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
$filteredValue | |||
); | |||
// $aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
// if (array_search($aliasRelation, $repositoryQuery->getAllAliases()) === false) { | |||
// $repositoryQuery->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
// } | |||
// $repositoryQuery->andWhere( | |||
// $fieldProperty.' = :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
// ); | |||
// $repositoryQuery->setParameter( | |||
// $this->getFieldPropertySnake($fieldProperty), | |||
// $filteredValue | |||
// ); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
$repositoryQuery->andWhere( | |||
'.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, $filteredValue); | |||
$repositoryQuery->setParameter($fieldProperty, $filteredValue); | |||
} | |||
} |
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -48,27 +49,27 @@ class ChoiceFilter | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue = null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery , string $fieldProperty, string $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
'%'.$filteredValue.'%' | |||
// if ($this->isRelationField($fieldProperty)) { | |||
// $aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
// if (array_search($aliasRelation, $repositoryQuery->getAllAliases()) === false) { | |||
// $repositoryQuery->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
// } | |||
// $repositoryQuery->andWhere( | |||
// $fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
// ); | |||
// $repositoryQuery->setParameter( | |||
// $this->getFieldPropertySnake($fieldProperty), | |||
// '%'.$filteredValue.'%' | |||
// ); | |||
// } else { | |||
$repositoryQuery->andWhere( | |||
'.'.$fieldProperty.' LIKE :'.$fieldProperty.'' | |||
); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' LIKE :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
} | |||
$repositoryQuery->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
} | |||
} | |||
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\FormType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -43,17 +44,17 @@ class DateFilter | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, \DateTime $dateStart = null, \DateTime $dateEnd = null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, \DateTime $dateStart = null, \DateTime $dateEnd = null) | |||
{ | |||
if ($dateStart) { | |||
$queryBuilder->andWhere( | |||
'entity.' . $fieldProperty . ' >= :dateStart' | |||
$repositoryQuery->andWhere( | |||
'.' . $fieldProperty . ' >= :dateStart' | |||
)->setParameter('dateStart', $dateStart); | |||
} | |||
if ($dateEnd) { | |||
$dateEnd->setTime(23, 59, 59); | |||
$queryBuilder->andWhere( | |||
'entity.' . $fieldProperty . ' <= :dateEnd' | |||
$repositoryQuery->andWhere( | |||
'.' . $fieldProperty . ' <= :dateEnd' | |||
)->setParameter('dateEnd', $dateEnd); | |||
} | |||
} |
@@ -3,12 +3,13 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\QueryBuilder; | |||
use DoctrineExtensions\Query\Mysql\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
@@ -38,7 +39,7 @@ class FilterManager | |||
} | |||
public function handleFiltersForm(QueryBuilder $queryBuilder, Form $filtersForm, $fields, EntityDto $entityDto) | |||
public function handleFiltersForm(RepositoryQueryInterface $repositoryQuery, Form $filtersForm, $fields, EntityDto $entityDto) | |||
{ | |||
foreach ($fields as $field) { | |||
@@ -71,7 +72,7 @@ class FilterManager | |||
$fieldDto->getProperty() | |||
); | |||
} | |||
$this->applyFilter($queryBuilder, $fieldDto, $filteredValue); | |||
$this->applyFilter($repositoryQuery, $fieldDto, $filteredValue); | |||
} | |||
} | |||
} | |||
@@ -87,43 +88,43 @@ class FilterManager | |||
return $property; | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, FieldDto $fieldDto, array $filteredValue) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, array $filteredValue) | |||
{ | |||
if ($fieldDto->getCustomOption('filter_fqcn')) { | |||
$filterFqcn = $fieldDto->getCustomOption('filter_fqcn'); | |||
$customFilter = new $filterFqcn; | |||
$customFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$customFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
} else { | |||
switch ($this->guessFormType($fieldDto)) { | |||
case CheckboxType::class: | |||
$checkboxFilter = new CheckboxFilter(); | |||
$checkboxFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$checkboxFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
break; | |||
case ChoiceType::class: | |||
$choiceFilter = new ChoiceFilter(); | |||
$choiceFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$choiceFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
break; | |||
case IntegerType::class: | |||
$integerFilter = new IntegerFilter(); | |||
$integerFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$integerFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
break; | |||
case TextareaType::class: | |||
case TextType::class: | |||
$textFilter = new TextFilter(); | |||
$textFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$textFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
break; | |||
case EntityType::class: | |||
$textFilter = new AssociationFilter(); | |||
$textFilter->applyFilter($queryBuilder, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
$textFilter->applyFilter($repositoryQuery, $this->getFieldProperty($fieldDto), $filteredValue['value']); | |||
break; | |||
case DateTimeType::class: | |||
case DateType::class: | |||
$textFilter = new DateFilter(); | |||
$textFilter->applyFilter( | |||
$queryBuilder, | |||
$repositoryQuery, | |||
$this->getFieldProperty($fieldDto), | |||
$filteredValue['dateStart'], | |||
$filteredValue['dateEnd'] |
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -36,16 +37,16 @@ class ImageFilter | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, $filteredValue = null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if($filteredValue === 1){ | |||
$queryBuilder->andWhere( | |||
'entity.' . $fieldProperty . ' IS NOT NULL' | |||
$repositoryQuery->andWhere( | |||
'.' . $fieldProperty . ' IS NOT NULL' | |||
); | |||
}else{ | |||
$queryBuilder->andWhere( | |||
'entity.' . $fieldProperty . ' IS NULL' | |||
$repositoryQuery->andWhere( | |||
'.' . $fieldProperty . ' IS NULL' | |||
); | |||
} | |||
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\IntegerType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -30,13 +31,13 @@ class IntegerFilter | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, string $filteredValue= null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
$repositoryQuery->andWhere( | |||
'.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, $filteredValue); | |||
$repositoryQuery->setParameter($fieldProperty, $filteredValue); | |||
} | |||
} | |||
@@ -2,8 +2,9 @@ | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Repository\RepositoryQueryInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
@@ -30,29 +31,29 @@ class TextFilter | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue = null) | |||
public function applyFilter(RepositoryQueryInterface $repositoryQuery, string $fieldProperty, string $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.' . $aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty . ' LIKE :' . $this->getFieldPropertySnake($fieldProperty) . '' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
'%' . $filteredValue . '%' | |||
// if ($this->isRelationField($fieldProperty)) { | |||
// | |||
// $aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
// if (array_search($aliasRelation, $repositoryQuery->getAllAliases()) === false) { | |||
// $repositoryQuery->innerJoin('entity.' . $aliasRelation, $aliasRelation); | |||
// } | |||
// $repositoryQuery->andWhere( | |||
// $fieldProperty . ' LIKE :' . $this->getFieldPropertySnake($fieldProperty) . '' | |||
// ); | |||
// $repositoryQuery->setParameter( | |||
// $this->getFieldPropertySnake($fieldProperty), | |||
// '%' . $filteredValue . '%' | |||
// ); | |||
// } else { | |||
$repositoryQuery->andWhere( | |||
'.' . $fieldProperty . ' LIKE :' . $fieldProperty . '' | |||
); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.' . $fieldProperty . ' LIKE :' . $fieldProperty . '' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, '%' . $filteredValue . '%'); | |||
} | |||
$repositoryQuery->setParameter($fieldProperty, '%' . $filteredValue . '%'); | |||
} | |||
} | |||
@@ -12,12 +12,6 @@ use Symfony\Component\Form\FormView; | |||
use Symfony\Component\OptionsResolver\Options; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
/** | |||
* Custom form type that deals with some of the logic used to render the | |||
* forms used to create and edit EasyAdmin entities. | |||
* | |||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com> | |||
*/ | |||
class CrudFormType extends AbstractType | |||
{ | |||
@@ -17,8 +17,6 @@ use Lc\SovBundle\Model\User\UserInterface; | |||
abstract class TicketModel extends AbstractLightEntity implements TicketInterface, EntityInterface | |||
{ | |||
const TYPE_TECHNICAL_PROBLEM = 'technical-problem'; | |||
const TYPE_GENERAL_QUESTION = 'general-question'; | |||
@@ -82,6 +82,11 @@ abstract class AbstractRepositoryQuery implements RepositoryQueryInterface | |||
return $this->repository; | |||
} | |||
public function getQueryBuilder(): QueryBuilder | |||
{ | |||
return $this->query; | |||
} | |||
protected function populateDqlId(&$data) | |||
{ | |||
if (is_string($data)) { |
@@ -0,0 +1,206 @@ | |||
<?php | |||
namespace Lc\SovBundle\Repository; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\QueryBuilder; | |||
use Doctrine\Persistence\ManagerRegistry; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Orm\EntityRepositoryInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FilterDataDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\FormFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\ComparisonType; | |||
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider; | |||
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository as EaEntityRepository; | |||
use Knp\Component\Pager\PaginatorInterface; | |||
use function Symfony\Component\Translation\t; | |||
class EntityRepository | |||
{ | |||
//protected EaEntityRepository $parent; | |||
protected EntityManagerInterface $entityManager; | |||
protected PaginatorInterface $paginator; | |||
public function __construct( | |||
//EaEntityRepository $entityRepository, | |||
EntityManagerInterface $entityManager, | |||
PaginatorInterface $paginator | |||
) { | |||
//$this->parent = $entityRepository; | |||
$this->entityManager = $entityManager; | |||
$this->paginator = $paginator; | |||
} | |||
public function createRepositoryQuery(RepositoryQueryInterface $repositoryQuery,SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters) | |||
{ | |||
// if (!empty($searchDto->getQuery())) { | |||
// $this->addSearchClause($repositoryQuery->getQuery(), $searchDto, $entityDto); | |||
// } | |||
// | |||
// if (!empty($searchDto->getAppliedFilters())) { | |||
// $this->addFilterClause($repositoryQuery->getQuery(), $searchDto, $entityDto, $filters, $fields); | |||
// } | |||
$this->addOrderClause($repositoryQuery, $searchDto, $entityDto); | |||
return $repositoryQuery; | |||
} | |||
private function addSearchClause(QueryBuilder $queryBuilder, SearchDto $searchDto, EntityDto $entityDto): void | |||
{ | |||
$query = $searchDto->getQuery(); | |||
$lowercaseQuery = mb_strtolower($query); | |||
$isNumericQuery = is_numeric($query); | |||
$isSmallIntegerQuery = ctype_digit($query) && $query >= -32768 && $query <= 32767; | |||
$isIntegerQuery = ctype_digit($query) && $query >= -2147483648 && $query <= 2147483647; | |||
$isUuidQuery = 1 === preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $query); | |||
$dqlParameters = [ | |||
// adding '0' turns the string into a numeric value | |||
'numeric_query' => is_numeric($query) ? 0 + $query : $query, | |||
'uuid_query' => $query, | |||
'text_query' => '%'.$lowercaseQuery.'%', | |||
'words_query' => explode(' ', $lowercaseQuery), | |||
]; | |||
$entitiesAlreadyJoined = []; | |||
$configuredSearchableProperties = $searchDto->getSearchableProperties(); | |||
$searchableProperties = empty($configuredSearchableProperties) ? $entityDto->getAllPropertyNames() : $configuredSearchableProperties; | |||
foreach ($searchableProperties as $propertyName) { | |||
if ($entityDto->isAssociation($propertyName)) { | |||
// support arbitrarily nested associations (e.g. foo.bar.baz.qux) | |||
$associatedProperties = explode('.', $propertyName); | |||
$numAssociatedProperties = \count($associatedProperties); | |||
if (1 === $numAssociatedProperties) { | |||
throw new \InvalidArgumentException(sprintf('The "%s" property included in the setSearchFields() method is not a valid search field. When using associated properties in search, you must also define the exact field used in the search (e.g. \'%s.id\', \'%s.name\', etc.)', $propertyName, $propertyName, $propertyName)); | |||
} | |||
$originalPropertyName = $associatedProperties[0]; | |||
$originalPropertyMetadata = $entityDto->getPropertyMetadata($originalPropertyName); | |||
$associatedEntityDto = $this->entityFactory->create($originalPropertyMetadata->get('targetEntity')); | |||
for ($i = 0; $i < $numAssociatedProperties - 1; ++$i) { | |||
$associatedEntityName = $associatedProperties[$i]; | |||
$associatedPropertyName = $associatedProperties[$i + 1]; | |||
if (!\in_array($associatedEntityName, $entitiesAlreadyJoined, true)) { | |||
$parentEntityName = 0 === $i ? 'entity' : $associatedProperties[$i - 1]; | |||
$queryBuilder->leftJoin($parentEntityName.'.'.$associatedEntityName, $associatedEntityName); | |||
$entitiesAlreadyJoined[] = $associatedEntityName; | |||
} | |||
if ($i < $numAssociatedProperties - 2) { | |||
$propertyMetadata = $associatedEntityDto->getPropertyMetadata($associatedPropertyName); | |||
$targetEntity = $propertyMetadata->get('targetEntity'); | |||
$associatedEntityDto = $this->entityFactory->create($targetEntity); | |||
} | |||
} | |||
$entityName = $associatedEntityName; | |||
$propertyName = $associatedPropertyName; | |||
$propertyDataType = $associatedEntityDto->getPropertyDataType($propertyName); | |||
} else { | |||
$entityName = 'entity'; | |||
$propertyDataType = $entityDto->getPropertyDataType($propertyName); | |||
} | |||
$isSmallIntegerProperty = 'smallint' === $propertyDataType; | |||
$isIntegerProperty = 'integer' === $propertyDataType; | |||
$isNumericProperty = \in_array($propertyDataType, ['number', 'bigint', 'decimal', 'float']); | |||
// 'citext' is a PostgreSQL extension (https://github.com/EasyCorp/EasyAdminBundle/issues/2556) | |||
$isTextProperty = \in_array($propertyDataType, ['string', 'text', 'citext', 'array', 'simple_array']); | |||
$isGuidProperty = \in_array($propertyDataType, ['guid', 'uuid']); | |||
// this complex condition is needed to avoid issues on PostgreSQL databases | |||
if ( | |||
($isSmallIntegerProperty && $isSmallIntegerQuery) || | |||
($isIntegerProperty && $isIntegerQuery) || | |||
($isNumericProperty && $isNumericQuery) | |||
) { | |||
$queryBuilder->orWhere(sprintf('%s.%s = :query_for_numbers', $entityName, $propertyName)) | |||
->setParameter('query_for_numbers', $dqlParameters['numeric_query']); | |||
} elseif ($isGuidProperty && $isUuidQuery) { | |||
$queryBuilder->orWhere(sprintf('%s.%s = :query_for_uuids', $entityName, $propertyName)) | |||
->setParameter('query_for_uuids', $dqlParameters['uuid_query']); | |||
} elseif ($isTextProperty) { | |||
$queryBuilder->orWhere(sprintf('LOWER(%s.%s) LIKE :query_for_text', $entityName, $propertyName)) | |||
->setParameter('query_for_text', $dqlParameters['text_query']); | |||
$queryBuilder->orWhere(sprintf('LOWER(%s.%s) IN (:query_as_words)', $entityName, $propertyName)) | |||
->setParameter('query_as_words', $dqlParameters['words_query']); | |||
} | |||
} | |||
} | |||
private function addOrderClause(RepositoryQueryInterface $repositoryQuery, SearchDto $searchDto, EntityDto $entityDto): void | |||
{ | |||
foreach ($searchDto->getSort() as $sortProperty => $sortOrder) { | |||
$repositoryQuery->addOrderBy('.'.$sortProperty, $sortOrder); | |||
// $aliases = $queryBuilder->getAllAliases(); | |||
// $sortFieldIsDoctrineAssociation = $entityDto->isAssociation($sortProperty); | |||
// | |||
// if ($sortFieldIsDoctrineAssociation) { | |||
// $sortFieldParts = explode('.', $sortProperty, 2); | |||
// // check if join has been added once before. | |||
// if (!\in_array($sortFieldParts[0], $aliases)) { | |||
// $queryBuilder->leftJoin('entity.'.$sortFieldParts[0], $sortFieldParts[0]); | |||
// } | |||
// | |||
// if (1 === \count($sortFieldParts)) { | |||
// $queryBuilder->addOrderBy('entity.'.$sortProperty, $sortOrder); | |||
// } else { | |||
// $queryBuilder->addOrderBy($sortProperty, $sortOrder); | |||
// } | |||
// } else { | |||
// $queryBuilder->addOrderBy('entity.'.$sortProperty, $sortOrder); | |||
// } | |||
} | |||
} | |||
private function addFilterClause(QueryBuilder $queryBuilder, SearchDto $searchDto, EntityDto $entityDto, FilterCollection $configuredFilters, FieldCollection $fields): void | |||
{ | |||
$filtersForm = $this->formFactory->createFiltersForm($configuredFilters, $this->adminContextProvider->getContext()->getRequest()); | |||
if (!$filtersForm->isSubmitted()) { | |||
return; | |||
} | |||
$appliedFilters = $searchDto->getAppliedFilters(); | |||
$i = 0; | |||
foreach ($filtersForm as $filterForm) { | |||
$propertyName = $filterForm->getName(); | |||
$filter = $configuredFilters->get($propertyName); | |||
// this filter is not defined or not applied | |||
if (null === $filter || !isset($appliedFilters[$propertyName])) { | |||
continue; | |||
} | |||
// if the form filter is not valid then we should not apply the filter | |||
if (!$filterForm->isValid()) { | |||
continue; | |||
} | |||
$submittedData = $filterForm->getData(); | |||
if (!\is_array($submittedData)) { | |||
$submittedData = [ | |||
'comparison' => ComparisonType::EQ, | |||
'value' => $submittedData, | |||
]; | |||
} | |||
$filterDataDto = FilterDataDto::new($i, $filter, current($queryBuilder->getRootAliases()), $submittedData); | |||
$filter->apply($queryBuilder, $filterDataDto, $fields->getByProperty($propertyName), $entityDto); | |||
++$i; | |||
} | |||
} | |||
} |
@@ -20,10 +20,17 @@ services: | |||
decorates: EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudFormType | |||
arguments: [ '@form.type_guesser.doctrine', '@.inner' ] | |||
Lc\SovBundle\Doctrine\EntityManager: | |||
public: false | |||
decoration_priority: 1 | |||
decorates: doctrine.orm.default_entity_manager | |||
arguments: ["@.inner"] | |||
arguments: [ "@.inner" ] | |||
# Lc\SovBundle\Repository\EntityRepository: | |||
# decorates: EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository | |||
# decoration_priority: 5 | |||
# arguments: [ "@.inner", '@doctrine.orm.default_entity_manager', '@Knp\Component\Pager\PaginatorInterface' ] | |||
Lc\SovBundle\Maker\: | |||
resource: '../../Maker/' |