Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1a6776e

Browse files
committed
feature EasyCorp#986 Add a new "dql_filter" configuration option (javiereguiluz)
This PR was squashed before being merged into the master branch (closes EasyCorp#986). Discussion ---------- Add a new "dql_filter" configuration option **NOTE**: this documentation explains a feature that doesn't exist yet. As usual, we first write the documentation, then ask the community and finally we implement the feature. Thoughts? Thanks! Commits ------- fac3433 Add a new "dql_filter" configuration option
2 parents 200d07d + fac3433 commit 1a6776e

16 files changed

Lines changed: 331 additions & 26 deletions

File tree

Configuration/NormalizerConfigPass.php

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,28 @@
2121
*/
2222
class NormalizerConfigPass implements ConfigPassInterface
2323
{
24+
private $defaultViewConfig = array(
25+
'list' => array(
26+
'dql_filter' => null,
27+
'fields' => array(),
28+
),
29+
'search' => array(
30+
'dql_filter' => null,
31+
'fields' => array(),
32+
),
33+
'show' => array(
34+
'fields' => array(),
35+
),
36+
'edit' => array(
37+
'fields' => array(),
38+
'form_options' => array(),
39+
),
40+
'new' => array(
41+
'fields' => array(),
42+
'form_options' => array(),
43+
),
44+
);
45+
2446
/** @var ContainerInterface */
2547
private $container;
2648

@@ -100,18 +122,16 @@ private function normalizeFormConfig(array $backendConfig)
100122
private function normalizeViewConfig(array $backendConfig)
101123
{
102124
foreach ($backendConfig['entities'] as $entityName => $entityConfig) {
103-
foreach (array('edit', 'list', 'new', 'search', 'show') as $view) {
104-
if (!isset($entityConfig[$view])) {
105-
$entityConfig[$view] = array('fields' => array());
106-
}
107-
108-
if (!isset($entityConfig[$view]['fields'])) {
109-
$entityConfig[$view]['fields'] = array();
110-
}
125+
// if the original 'search' config doesn't define its own DQL filter, use the one form 'list'
126+
if (!isset($entityConfig['search']) || !array_key_exists('dql_filter', $entityConfig['search'])) {
127+
$entityConfig['search']['dql_filter'] = isset($entityConfig['list']['dql_filter']) ? $entityConfig['list']['dql_filter'] : null;
128+
}
111129

112-
if (in_array($view, array('edit', 'new')) && !isset($entityConfig[$view]['form_options'])) {
113-
$entityConfig[$view]['form_options'] = array();
114-
}
130+
foreach (array('edit', 'list', 'new', 'search', 'show') as $view) {
131+
$entityConfig[$view] = array_replace_recursive(
132+
$this->defaultViewConfig[$view],
133+
isset($entityConfig[$view]) ? $entityConfig[$view] : array()
134+
);
115135
}
116136

117137
$backendConfig['entities'][$entityName] = $entityConfig;

Controller/AdminController.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ protected function listAction()
156156
$this->dispatch(EasyAdminEvents::PRE_LIST);
157157

158158
$fields = $this->entity['list']['fields'];
159-
$paginator = $this->findAll($this->entity['class'], $this->request->query->get('page', 1), $this->config['list']['max_results'], $this->request->query->get('sortField'), $this->request->query->get('sortDirection'));
159+
$paginator = $this->findAll($this->entity['class'], $this->request->query->get('page', 1), $this->config['list']['max_results'], $this->request->query->get('sortField'), $this->request->query->get('sortDirection'), $this->entity['list']['dql_filter']);
160160

161161
$this->dispatch(EasyAdminEvents::POST_LIST, array('paginator' => $paginator));
162162

@@ -362,7 +362,7 @@ protected function searchAction()
362362
}
363363

364364
$searchableFields = $this->entity['search']['fields'];
365-
$paginator = $this->findBy($this->entity['class'], $this->request->query->get('query'), $searchableFields, $this->request->query->get('page', 1), $this->config['list']['max_results'], $this->request->query->get('sortField'), $this->request->query->get('sortDirection'));
365+
$paginator = $this->findBy($this->entity['class'], $this->request->query->get('query'), $searchableFields, $this->request->query->get('page', 1), $this->config['list']['max_results'], $this->request->query->get('sortField'), $this->request->query->get('sortDirection'), $this->entity['search']['dql_filter']);
366366
$fields = $this->entity['list']['fields'];
367367

368368
$this->dispatch(EasyAdminEvents::POST_SEARCH, array(
@@ -459,16 +459,17 @@ protected function preRemoveEntity($entity)
459459
* @param int $maxPerPage
460460
* @param string|null $sortField
461461
* @param string|null $sortDirection
462+
* @param string|null $dqlFilter
462463
*
463464
* @return Pagerfanta The paginated query results
464465
*/
465-
protected function findAll($entityClass, $page = 1, $maxPerPage = 15, $sortField = null, $sortDirection = null)
466+
protected function findAll($entityClass, $page = 1, $maxPerPage = 15, $sortField = null, $sortDirection = null, $dqlFilter = null)
466467
{
467468
if (empty($sortDirection) || !in_array(strtoupper($sortDirection), array('ASC', 'DESC'))) {
468469
$sortDirection = 'DESC';
469470
}
470471

471-
$queryBuilder = $this->executeDynamicMethod('create<EntityName>ListQueryBuilder', array($entityClass, $sortDirection, $sortField));
472+
$queryBuilder = $this->executeDynamicMethod('create<EntityName>ListQueryBuilder', array($entityClass, $sortDirection, $sortField, $dqlFilter));
472473

473474
$this->dispatch(EasyAdminEvents::POST_LIST_QUERY_BUILDER, array(
474475
'query_builder' => $queryBuilder,
@@ -485,12 +486,13 @@ protected function findAll($entityClass, $page = 1, $maxPerPage = 15, $sortField
485486
* @param string $entityClass
486487
* @param string $sortDirection
487488
* @param string|null $sortField
489+
* @param string|null $dqlFilter
488490
*
489491
* @return QueryBuilder The Query Builder instance
490492
*/
491-
protected function createListQueryBuilder($entityClass, $sortDirection, $sortField = null)
493+
protected function createListQueryBuilder($entityClass, $sortDirection, $sortField = null, $dqlFilter = null)
492494
{
493-
return $this->get('easyadmin.query_builder')->createListQueryBuilder($this->entity, $sortField, $sortDirection);
495+
return $this->get('easyadmin.query_builder')->createListQueryBuilder($this->entity, $sortField, $sortDirection, $dqlFilter);
494496
}
495497

496498
/**
@@ -504,12 +506,13 @@ protected function createListQueryBuilder($entityClass, $sortDirection, $sortFie
504506
* @param int $maxPerPage
505507
* @param string|null $sortField
506508
* @param string|null $sortDirection
509+
* @param string|null $dqlFilter
507510
*
508511
* @return Pagerfanta The paginated query results
509512
*/
510-
protected function findBy($entityClass, $searchQuery, array $searchableFields, $page = 1, $maxPerPage = 15, $sortField = null, $sortDirection = null)
513+
protected function findBy($entityClass, $searchQuery, array $searchableFields, $page = 1, $maxPerPage = 15, $sortField = null, $sortDirection = null, $dqlFilter = null)
511514
{
512-
$queryBuilder = $this->executeDynamicMethod('create<EntityName>SearchQueryBuilder', array($entityClass, $searchQuery, $searchableFields, $sortField, $sortDirection));
515+
$queryBuilder = $this->executeDynamicMethod('create<EntityName>SearchQueryBuilder', array($entityClass, $searchQuery, $searchableFields, $sortField, $sortDirection, $dqlFilter));
513516

514517
$this->dispatch(EasyAdminEvents::POST_SEARCH_QUERY_BUILDER, array(
515518
'query_builder' => $queryBuilder,
@@ -528,12 +531,13 @@ protected function findBy($entityClass, $searchQuery, array $searchableFields, $
528531
* @param array $searchableFields
529532
* @param string|null $sortField
530533
* @param string|null $sortDirection
534+
* @param string|null $dqlFilter
531535
*
532536
* @return QueryBuilder The Query Builder instance
533537
*/
534-
protected function createSearchQueryBuilder($entityClass, $searchQuery, array $searchableFields, $sortField = null, $sortDirection = null)
538+
protected function createSearchQueryBuilder($entityClass, $searchQuery, array $searchableFields, $sortField = null, $sortDirection = null, $dqlFilter = null)
535539
{
536-
return $this->get('easyadmin.query_builder')->createSearchQueryBuilder($this->entity, $searchQuery, $sortField, $sortDirection);
540+
return $this->get('easyadmin.query_builder')->createSearchQueryBuilder($this->entity, $searchQuery, $sortField, $sortDirection, $dqlFilter);
537541
}
538542

539543
/**

Resources/doc/book/3-list-search-show-configuration.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,95 @@ easy_admin:
374374
The main limitation of virtual properties is that you cannot sort listings
375375
using these fields.
376376
377+
Filtering Entities
378+
------------------
379+
380+
A common need for backends is to filter the entities included in listings (for
381+
example: don't display expired offers, display only clients that spend more than
382+
a given amount, etc.) You can achieve this with the features explained later in
383+
this chapter to modify the behavior of the `list`, `search` and `show` views.
384+
385+
However, for simple filters it's more convenient to use the `dql_filter` option,
386+
which defines the conditions passed to the `WHERE` clause of the Doctrine query
387+
used to get the entities displayed in the `list` and `search` views.
388+
389+
The following example manages the same `User` entity in two different ways using
390+
a basic filter to differentiate each type of user:
391+
392+
```yaml
393+
easy_admin:
394+
entities:
395+
VipCustomers:
396+
class: AppBundle\Entity\User
397+
list:
398+
dql_filter: 'entity.budget > 100000'
399+
RegularCustomers:
400+
class: AppBundle\Entity\User
401+
list:
402+
dql_filter: 'entity.budget <= 100000'
403+
```
404+
405+
The Doctrine DQL expression defined in the `dql_filter` option must always use
406+
`entity` as the name of the entity, regardless of your actual entity name.
407+
408+
Since this is a regular YAML configuration file, you can also include container
409+
parameters inside the filter to use different values depending on the environment
410+
or even dynamic values:
411+
412+
```yaml
413+
easy_admin:
414+
entities:
415+
VipCustomers:
416+
class: AppBundle\Entity\User
417+
list:
418+
dql_filter: 'entity.budget > %customers.budget_threshold%'
419+
# ...
420+
```
421+
422+
The value of the `dql_filter` can combine several conditions (in fact, you can
423+
put anything that is considered valid as a `WHERE` clause in a Doctrine query):
424+
425+
```yaml
426+
easy_admin:
427+
entities:
428+
UrgentIssues:
429+
class: AppBundle\Entity\Issue
430+
list:
431+
dql_filter: 'entity.label == "CRITICAL" OR entity.priority > 4'
432+
ImportantIssues:
433+
class: AppBundle\Entity\Issue
434+
list:
435+
dql_filter: 'entity.priority > 2 AND entity.numComments > 10'
436+
AllIssues:
437+
class: AppBundle\Entity\Issue
438+
```
439+
440+
> **NOTE**
441+
>
442+
> By default the `dql_filter` option from the `list` view is also used in the
443+
> `search` view. If you prefer to apply different filters, define the
444+
> `dql_filter` option explicitly for the `search` view:
445+
>
446+
> ```yaml
447+
> easy_admin:
448+
> entities:
449+
> Issues:
450+
> class: AppBundle\Entity\Issue
451+
> list:
452+
> dql_filter: "LOWER(entity.title) LIKE '%%issue%%'"
453+
> search:
454+
> # defining a different condition than 'list'
455+
> dql_filter: 'entity.status != "DELETED"'
456+
> # using an empty value to not apply any condition when searching
457+
> # elements (this prevents inheriting the 'dql_filter' value defined in 'list')
458+
> dql_filter: ''
459+
> ```
460+
461+
> **TIP**
462+
>
463+
> Combine the `dql_filter` option with a custom menu (as explained in the next
464+
> chapters) to improve the navigation of the backend.
465+
377466
Property Types Defined by EasyAdmin
378467
-----------------------------------
379468

Search/QueryBuilder.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ public function __construct(Registry $doctrine)
3232
* Creates the query builder used to get all the records displayed by the
3333
* "list" view.
3434
*
35-
* @param array $entityConfig
36-
* @param string $sortDirection
37-
* @param string $sortField
35+
* @param array $entityConfig
36+
* @param string|null $sortField
37+
* @param string|null $sortDirection
38+
* @param string|null $dqlFilter
3839
*
3940
* @return DoctrineQueryBuilder
4041
*/
41-
public function createListQueryBuilder(array $entityConfig, $sortField = null, $sortDirection = null)
42+
public function createListQueryBuilder(array $entityConfig, $sortField = null, $sortDirection = null, $dqlFilter = null)
4243
{
4344
/* @var EntityManager */
4445
$em = $this->doctrine->getManagerForClass($entityConfig['class']);
@@ -48,6 +49,10 @@ public function createListQueryBuilder(array $entityConfig, $sortField = null, $
4849
->from($entityConfig['class'], 'entity')
4950
;
5051

52+
if (!empty($dqlFilter)) {
53+
$queryBuilder->andWhere($dqlFilter);
54+
}
55+
5156
if (null !== $sortField) {
5257
$queryBuilder->orderBy('entity.'.$sortField, $sortDirection);
5358
}
@@ -63,10 +68,11 @@ public function createListQueryBuilder(array $entityConfig, $sortField = null, $
6368
* @param string $searchQuery
6469
* @param string|null $sortField
6570
* @param string|null $sortDirection
71+
* @param string|null $dqlFilter
6672
*
6773
* @return DoctrineQueryBuilder
6874
*/
69-
public function createSearchQueryBuilder(array $entityConfig, $searchQuery, $sortField = null, $sortDirection = null)
75+
public function createSearchQueryBuilder(array $entityConfig, $searchQuery, $sortField = null, $sortDirection = null, $dqlFilter = null)
7076
{
7177
/* @var EntityManager */
7278
$em = $this->doctrine->getManagerForClass($entityConfig['class']);
@@ -100,6 +106,10 @@ public function createSearchQueryBuilder(array $entityConfig, $searchQuery, $sor
100106
$queryBuilder->setParameters($queryParameters);
101107
}
102108

109+
if (!empty($dqlFilter)) {
110+
$queryBuilder->andWhere($dqlFilter);
111+
}
112+
103113
if (null !== $sortField) {
104114
$queryBuilder->orderBy('entity.'.$sortField, $sortDirection ?: 'DESC');
105115
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# TEST
2+
# if the entity doesn't define a dql_filter option explicitly for 'list' or
3+
# 'search' its value will be considered as null
4+
5+
# CONFIGURATION
6+
easy_admin:
7+
entities:
8+
Category:
9+
class: AppTestBundle\Entity\UnitTests\Category
10+
list: ~
11+
search: ~
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# TEST
2+
# if the entity defines a dql_filter option for 'list' and not for 'search',
3+
# its value will be used for 'search' too
4+
5+
# CONFIGURATION
6+
easy_admin:
7+
entities:
8+
Category:
9+
class: AppTestBundle\Entity\UnitTests\Category
10+
list:
11+
dql_filter: "entity.id > 10 AND entity.name LIKE '%%Subcategory%%'"
12+
search: ~
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# TEST
2+
# if the entity defines a dql_filter option for 'list' and for 'search', use the
3+
# appropriate value for each view
4+
5+
# CONFIGURATION
6+
easy_admin:
7+
entities:
8+
Category:
9+
class: AppTestBundle\Entity\UnitTests\Category
10+
list:
11+
dql_filter: "entity.id > 10 AND entity.name LIKE '%%Subcategory%%'"
12+
search:
13+
dql_filter: 'entity.id < 200 OR entity.name != "Deprecated"'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# TEST
2+
# if the entity defines a dql_filter option for 'list', the 'search' view can set
3+
# this option to an empty value to not use the same dql_filter as 'list'
4+
5+
# CONFIGURATION
6+
easy_admin:
7+
entities:
8+
Category:
9+
class: AppTestBundle\Entity\UnitTests\Category
10+
list:
11+
dql_filter: "entity.id > 10 AND entity.name LIKE '%%Subcategory%%'"
12+
search:
13+
dql_filter: ''
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# TEST
2+
# if the entity defines a dql_filter option for 'list', the 'search' view can set
3+
# this option to null to not use the same dql_filter as 'list'
4+
5+
# CONFIGURATION
6+
easy_admin:
7+
entities:
8+
Category:
9+
class: AppTestBundle\Entity\UnitTests\Category
10+
list:
11+
dql_filter: "entity.id > 10 AND entity.name LIKE '%%Subcategory%%'"
12+
search:
13+
dql_filter: ~
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
easy_admin:
2+
entities:
3+
Category:
4+
class: AppTestBundle\Entity\UnitTests\Category
5+
list:
6+
dql_filter: null
7+
search:
8+
dql_filter: null

0 commit comments

Comments
 (0)