ソースを参照

Intégration des RepositoryQuery dans EasyAdmin

feature/symfony6.1
Fabien Normand 2年前
コミット
a40c4f105d
21個のファイルの変更433行の追加180行の削除
  1. +36
    -28
      Controller/AbstractAdminController.php
  2. +44
    -41
      Controller/ControllerTrait.php
  3. +5
    -0
      Controller/Newsletter/NewsletterAdminController.php
  4. +6
    -0
      Controller/Site/NewsAdminController.php
  5. +6
    -0
      Controller/Site/PageAdminController.php
  6. +6
    -5
      Controller/Ticket/TicketAdminController.php
  7. +5
    -0
      Controller/User/GroupUserAdminController.php
  8. +2
    -0
      Doctrine/EntityManager.php
  9. +14
    -14
      Field/Filter/AssociationFilter.php
  10. +17
    -16
      Field/Filter/CheckboxFilter.php
  11. +20
    -19
      Field/Filter/ChoiceFilter.php
  12. +7
    -6
      Field/Filter/DateFilter.php
  13. +12
    -11
      Field/Filter/FilterManager.php
  14. +7
    -6
      Field/Filter/ImageFilter.php
  15. +6
    -5
      Field/Filter/IntegerFilter.php
  16. +21
    -20
      Field/Filter/TextFilter.php
  17. +0
    -6
      Form/Common/CrudFormType.php
  18. +0
    -2
      Model/Ticket/TicketModel.php
  19. +5
    -0
      Repository/AbstractRepositoryQuery.php
  20. +206
    -0
      Repository/EntityRepository.php
  21. +8
    -1
      Resources/config/services.yaml

+ 36
- 28
Controller/AbstractAdminController.php ファイルの表示

@@ -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(

+ 44
- 41
Controller/ControllerTrait.php ファイルの表示

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

+ 5
- 0
Controller/Newsletter/NewsletterAdminController.php ファイルの表示

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

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

+ 6
- 0
Controller/Site/NewsAdminController.php ファイルの表示

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

abstract class NewsAdminController extends AbstractAdminController
{

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

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

+ 6
- 0
Controller/Site/PageAdminController.php ファイルの表示

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

abstract class PageAdminController extends AbstractAdminController
{

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

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

+ 6
- 5
Controller/Ticket/TicketAdminController.php ファイルの表示

@@ -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')

+ 5
- 0
Controller/User/GroupUserAdminController.php ファイルの表示

@@ -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
{

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

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

/**

+ 14
- 14
Field/Filter/AssociationFilter.php ファイルの表示

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

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

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

+ 17
- 16
Field/Filter/CheckboxFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -34,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);
}

}

+ 20
- 19
Field/Filter/ChoiceFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -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.'%');

}
}


+ 7
- 6
Field/Filter/DateFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -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);
}
}

+ 12
- 11
Field/Filter/FilterManager.php ファイルの表示

@@ -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']

+ 7
- 6
Field/Filter/ImageFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Symfony\Component\Form\Extension\Core\Type\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'
);
}


+ 6
- 5
Field/Filter/IntegerFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

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

@@ -30,13 +31,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);
}
}


+ 21
- 20
Field/Filter/TextFilter.php ファイルの表示

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

namespace Lc\SovBundle\Field\Filter;

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

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

}
}


+ 0
- 6
Form/Common/CrudFormType.php ファイルの表示

@@ -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
{


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

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


+ 5
- 0
Repository/AbstractRepositoryQuery.php ファイルの表示

@@ -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)) {

+ 206
- 0
Repository/EntityRepository.php ファイルの表示

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

namespace Lc\SovBundle\Repository;

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

class EntityRepository
{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

++$i;
}
}



}

+ 8
- 1
Resources/config/services.yaml ファイルの表示

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

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