If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWhat else could we possibly configure with the list view? How about sorting, or filtering list via DQL. OoooOOooo.
First, sorting... which we get for free. Already, the genuses are sorted by id, but we can click any column to sort by that. But this isn't sticky: when you come back to the genus list page, it's back to filtering by id.
Sorting by name would be a bit more awesome. And you can probably guess what the config looks like to do this. Under Genus
and list
, add sort: name
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
Genus: | |
... lines 92 - 94 | |
list: | |
... lines 96 - 106 | |
sort: 'name' | |
... lines 108 - 136 |
This is the new default field for sorting.
Oh, but we can get fancier. Under GenusNote
, what if I told you I wanted to sort by the name of the Genus
it's related to? Yea, that would mean sorting across a relation. But that's totally possible: sort: ['genus.name', 'ASC']
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusNote: | |
... lines 112 - 113 | |
list: | |
... lines 115 - 121 | |
sort: ['genus.name', 'ASC'] | |
... lines 123 - 137 |
This also controls the direction. It sorts descending by default.
Try it! Nice! This works... just don't get too confident and try to do this across multiple relationships... that's not going to work.
The ability to sort via any field with no setup is great! Though... sometimes it doesn't make sense - like with the "User avatar" field. To tighten things up, you can disable sorting. Find that field's list
config and add a new option at the end: sortable: false
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusNote: | |
... lines 112 - 113 | |
list: | |
... line 115 | |
fields: | |
... lines 117 - 118 | |
- { property: 'userAvatarFilename', label: 'User avatar', type: 'image', base_path: '/images/', sortable: false } | |
... lines 120 - 137 |
And... gone!
Ok, let's turn to something fun: DQL filtering. Like, what if we want to hide some genuses entirely from the list and search page?
But first, so far, it seems like we're limited to one entity section per entity. That's a lie! Let me show you: add a new section under entities
called GenusHorde
- I just made that up. Below, set its class to AppBundle\Entity\Genus
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
class: AppBundle\Entity\Genus |
You see, some scientists are worried that certain genuses are becoming too large... and threaten the survival of mankind. They want a new GenusHorde
section where they can keep track of all of the genuses that have a lot of species. It's scary stuff, so we'll add a label: HORDE of Genuses
with a scary icon:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
class: AppBundle\Entity\Genus | |
label: HORDE of Genuses ? !!! | |
... lines 114 - 140 |
Tip
Fun fact! You can press Control
+Command
+Space
to open up the icon menu on a Mac.
And all of a sudden... ah! We have a new "Horde of Genuses" section! Run!!!
Of course, this still shows all genuses. I want to filter this to only list genuses that have a lot of species. Start by adding a list
key and a new, awe-inspiring option: dql_filter
. For the value, pretend that you're building a query in Doctrine. So, entity.speciedCount >= 50000
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
... lines 112 - 113 | |
list: | |
dql_filter: 'entity.speciesCount >= 50000' | |
... lines 116 - 142 |
The alias will always be entity
.
Try it! Ten down to... only 7 menacing genuses!
And just like any query, you can get more complex. How about: AND entity.isPublished = true
:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
... lines 112 - 113 | |
list: | |
dql_filter: 'entity.speciesCount >= 50000 AND entity.isPublished = true' | |
... lines 116 - 144 |
And to really focus on the genuses that are certain to overtake humanity, sort it by speciesCount
and give the section a helpful message: Run for your life!!!
Add scary icons for emphasis:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
... lines 112 - 113 | |
list: | |
dql_filter: 'entity.speciesCount >= 50000 AND entity.isPublished = true' | |
sort: 'speciesCount' | |
help: Run for your life!!! ??? | |
... lines 118 - 144 |
Ok... refresh! Ah... now only three genuses are threatening mankind.
Oh, and search automatically re-uses the dql_filter
from list: these are 2 results from the possible 3. And like always, you can override this. Under search
, set the dql_filter
to the same value, but without the isPublished
check:
... lines 1 - 80 | |
easy_admin: | |
... lines 82 - 89 | |
entities: | |
... lines 91 - 110 | |
GenusHorde: | |
... lines 112 - 117 | |
search: | |
dql_filter: 'entity.speciesCount >= 50000' | |
... lines 120 - 146 |
Try that. Boom! 3 more genuses that - when published - will spell certain doom for all.
Next! We'll save humanity by learning how to override the many templates that EasyAdminBundle uses.
Hey Brent !
Excellent question. Hmm, that is a bit tricky. In a normal query, I would do something like andWhere('whenEntered > :now')->setParameter('now', new \DateTime())
, but we can't do that inside of YAML. So, we'll need to apply the dql_filter manually (not in YAML). There are a few ways to do this, but the one I'd use is an event:
1) Add an event listener (https://symfonycasts.com/screencast/easyadminbundle/event-hooks) on an event called EasyAdminEvents::POST_LIST_QUERY_BUILDER (which is the string easy_admin.post_list_query_builder
).
2) Your listener function will be passed a GenericEvent
object, but with a query_builder
argument on it that you can mess with - something like this:
public function onPostListQueryBuilder(GenericEvent $event)
{
// make sure to only modify the query for the one entity
if (!$event->getSubject() instanceof YourTargetEntity::class) {
return;
}
$queryBuilder = $event->getArgument('query_builder');
$queryBuilder->andWhere('entity.whenEntered > :now')
->setParameter('now', new \DateTime());
}
I haven't tested this, but that should do the trick :). Let me know if you have any issues. You might also want to add another event listener on the EasyAdminEvents::POST_LIST_QUERY_BUILDER
event.
Cheers!
Hi team !
I need to add an advance search feature. Ex filter the list view by sub-family.
I don't think I've seen such feature in this course (maybe I'm missing something?).
So I checked the doc, but I didn't found anything except this : https://github.com/javiereg...
but this is only a proposal.
Do you have any idea how to implement this kind of filter ?
Best regards.
Yo Kaizoku!
Hmm. How would your search field work exactly? I mean, would I type in the name of the sub-family and it would find all Genus that are related to that Sub-Family? Or would you have some sort of drop-down to select the sub-family? Regardless of what you need exactly, keep in mind that the searchAction
is just an action that creates a custom paginator and then renders the list template: https://github.com/javiereguiluz/EasyAdminBundle/blob/aac1732adc3ac1401dc08dca756ea19708a248af/src/Controller/AdminController.php#L347. So, in theory, I think you could override this, create your own paginator by using whatever logic you want, and then render the same template :).
Cheers!
[edit : remove code part as this isn't easy to read. If someone want code example send me an email.]
Thank you Ryan for the suggestion.
Here is how I choose to implement a dynamic DQL filter.
As suggested I overrided the search template
{% extends '@EasyAdmin/default/list.html.twig' %}
{% block search_action %} Copie paste original code and add your custom form code.{% endblock %}
This will give you 2 drop down select box along the search input.
Now about the controller.
The filters I need are specific to only one entity and it should apply to the list and search view.
So I went for the "Customization Based on Entity Controllers" option.
https://symfony.com/doc/current/bundles/EasyAdminBundle/book/complex-dynamic-backends.html#customization-based-on-entity-controllers
I created a specific controller and override the list and search action.
In both method I added a form with the filters I needed.
And the trick is to use the dql_filter parameter provided in the searchAction.
It's the same parameter that is hardcoded in the config file in this video, but this time it's changed by the user.
It works very well.
The only problem is that it's not possible to make complex filter action as according to the doc you can put only WHERE condition in the $dql_filter parameter.
For instance I needed a filter based on a JOIN and I couldn't find how to do this.
I think this is a very usefull case - Backend dynamic DQL Filter - and maybe it can be added in a futur video ;)
Here is how the controler looks like.
namespace App\Controller;
...
use EasyCorp\Bundle\EasyAdminBundle\Controller\AdminController as BaseAdminController;
class AdminCandidatureController extends BaseAdminController
{
public function listAction()
{
// copy/paste code from the parent listAction
// Add a Symfony form
return $this->render( ...);
}
public function searchAction()
{
$this->dispatch(EasyAdminEvents::PRE_SEARCH);
$query = trim($this->request->query->get('query'));
$filter_diplome = trim($this->request->query->get('frm_diplome'));
$filter_offre = trim($this->request->query->get('frm_offre'));
$dql_filter = '';
if ($filter_diplome) {
$dql_filter = 'entity.diplome = '.$filter_diplome;
}
if ($filter_offre) {
if ($dql_filter) {
$dql_filter .= ' AND ';
}
$dql_filter .= 'entity.offer = '.$filter_offre;
}
// if the search query is empty, redirect to the 'list' action
if ('' === $query &&
'' === $filter_diplome &&
'' === $filter_offre
) {
// copie paste original code
}
// copie paste original code, change $this->entity['search']['dql_filter'] by $dql_filter in the paginator object
//add the same form we created in the list view
return $this->render( ... );
}
}
Nice work! And thanks for sharing (and even using the code blocks from Disqus - woo!). I agree on the DQL filtering limitation - it's a bummer. Currently , there are a bunch of little things like this in EasyAdminBundle - Javier (the maintainer) is balancing staying simple... which means not solving *every* problem. I get it - it's but yea, when you find a feature you want that's not there, it's no fun :).
Cheers!
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.3.*", // v3.3.18
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
"symfony/swiftmailer-bundle": "^2.3", // v2.6.7
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.17.0
"sensio/distribution-bundle": "^5.0", // v5.0.25
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
"incenteev/composer-parameter-handler": "^2.0", // v2.1.4
"knplabs/knp-markdown-bundle": "^1.4", // 1.7.1
"doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
"stof/doctrine-extensions-bundle": "^1.2", // v1.3.0
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"javiereguiluz/easyadmin-bundle": "^1.16" // v1.17.21
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.7
"symfony/phpunit-bridge": "^3.0", // v3.4.40
"nelmio/alice": "^2.1", // v2.3.5
"doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
}
}
Hi,
I have an entity with two date fields (when entered, due date). Does dql_filter support filtering a date field (eg. whenentered >= now)? I'm having trouble finding an example of this. Thank you in advance.