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 SubscribeWe know that a field describes both the form type that you see on the form and also how that field is rendered on the detail and index pages. We also know how easy it is to customize the form type. We can ->setFormType()
to use a completely different type or ->setFormTypeOption()
to configure that type.
We can also change a lot about how each renders on the detail and index pages. For example, let's play with this "Votes" field:
... lines 1 - 9 | |
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField; | |
class AnswerCrudController extends AbstractCrudController | |
{ | |
... lines 14 - 18 | |
public function configureFields(string $pageName): iterable | |
{ | |
... lines 21 - 23 | |
yield IntegerField::new('votes'); | |
... lines 25 - 31 | |
} | |
} |
If I autocomplete the methods on this, we have options like ->setCssClass()
, ->addWebpackEncoreEntries()
, ->addHtmlContentsToBody()
, and ->addHtmlContentsToHead()
. You can even call ->setTemplatePath()
to completely override how this field is rendered on the index and detail pages, which we'll do in a moment.
But also notice that there's ->setTemplatePath()
and ->setTemplateName()
. What's the difference?
To answer that question, I'm going to hit Shift
+ Shift
and open up a core class from EasyAdmin called TemplateRegistry.php
. If you don't see it, make sure to "Include non-project items".
Perfect! Internally, EasyAdmin has many templates and it maintains this "map" of template names to the template filename behind each. So when you call ->setTemplateName()
, what you would pass is some other template name. For example, I could pass crud/field/money
if I wanted to use that template instead of the normal one.
But you probably won't override the template name very often. Most of the time, if you want to completely control how a field is rendered, you'll call ->setTemplatePath()
.
Here's the plan: when "Votes" is rendered on the index and detail pages, I want to render a completely different template. Let's call it admin/field/votes.html.twig
:
... lines 1 - 11 | |
class AnswerCrudController extends AbstractCrudController | |
{ | |
... lines 14 - 18 | |
public function configureFields(string $pageName): iterable | |
{ | |
... lines 21 - 23 | |
yield IntegerField::new('votes') | |
->setTemplatePath('admin/field/votes.html.twig'); | |
... lines 26 - 32 | |
} | |
} |
Ok! Time to create that. In templates/
, add 2 new directories admin/field
... and a new file: votes.html.twig
. Inside, I don't really know what to put here yet, so I'll just put "💯 votes!"... and see what happens:
💯 votes! |
When we move over and refresh... there it is! We are now in complete control of the votes!
But, if you're like me, you're probably wondering what we can do inside of here. What variables do we have access to? One important thing to realize (and you can see it here in TemplateRegistry.php
) is that every single field has a corresponding template. If you need to extend or change how a field is rendered, looking into the core template is pretty handy.
For example, votes
is an IntegerField
. Whelp, there's a template called integer.html.twig
. Close this template registry and... let's go find that! Open vendor/easycorp/easyadmin-bundle/src/
... close up Field/
and instead open Resources/views/crud/field
. Here is the list of all of the field templates in the system. You can also see other templates that are used to render other parts of EasyAdmin... and you can override these as well.
Open up integer.html.twig
. Ok cool. Check out the collection of comments on top. I like this! It helps our editor (and us) to know which variables we have access to. Apparently, we have access to a field
variable, which is that familiar FieldDto
object we talked about earlier. All the integer template does is just... print field.formattedValue
.
Copy these three lines and paste them into our votes.html.twig
:
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} | |
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |
... lines 4 - 5 |
Then instead of "💯 votes!", say field.formattedValue
"votes":
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} | |
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |
{{ field.formattedValue }} votes |
And when we try this... beautiful! But I bet we can make this fancier! If the votes are negative, let's put a little thumbs down. And if positive, a thumbs up.
Take off the word "votes"... and add if field.
. Hmm. What we want to get is the underlying value - the true integer
, not necessarily the "formatted" value. We can get that by saying field.value
.
So formattedValue
is the string that would print on the page, while value
is the actual underlying (in this case) integer. So if field.value >= 0
, else
, and endif
:
... lines 1 - 3 | |
{% if field.value >= 0 %} | |
... line 5 | |
{% else %} | |
... line 7 | |
{% endif %} | |
{{ field.formattedValue }} |
If it is greater than zero, add an icon with fas fa-thumbs-up text-success
. Copy that... and paste for our thumbs down with text-danger
:
... lines 1 - 3 | |
{% if field.value >= 0 %} | |
<i class="fas fa-thumbs-up text-success"></i> | |
{% else %} | |
<i class="fas fa-thumbs-down text-danger"></i> | |
{% endif %} | |
... lines 9 - 10 |
And... just like that, we're making this field render however we want. It doesn't change how it looks like inside of the form (that's entirely handled by the form type), but it does control how it's rendered on the index page, and the detail page.
But, hmm. We also have a "votes" field inside of the Questions section. While it would be pretty easy to also point that votes field to the same new template, instead, I want to create a brand new custom field in EasyAdmin. That's next.
Whoops, we're sorry about that! It should be good now, I re-upload the video. Let us know if you still have some troubles with playing it
Cheers!
Hey Dzianisr,
We're sorry about that! Looks like uploading was incomplete, I just re-uploaded this video again, now it should work!
Cheers!
Hi, video not works : "The media could not be loaded, either because the server or network failed or because the format is not supported."
Hey Sébastien,
Thank you for reporting this! The video was re-uploaded, it should be fixed now. We're sorry for the inconveniences! Let us know if you still have any troubles with playing it.
Cheers!
Hey Sébastien,
I'm sorry for that again! That's weird, but I just re-uploaded the video again, it should work now... at least it works for me.
Cheers!
Hi Ryan,
thanks for the awesome content as always!
We saw that we can use setTemplatePath()
to set our own template for a field in the ['index', 'detail'] pages.
But is there a way to set a custom template for a field in the post pages? I tried to dig a little bit in the library but I got a bit lost.
If the answer is related to setFormType()
then how can we create our own TypeClass with its custom template?
I want to convert my user roles json field to something like this: https://i.stack.imgur.com/26TlM.png
Thanks a lot in advanced :)
Hey Omar!
Excellent question! You're 100% right that setTemplatePath()
is NOT the way - that's only for "rendering"/displaying the field - it doesn't affect how the form renders at all.
The form is rendered entirely via the form system. In fact, here is the template that, for example, renders the "edit" form: https://github.com/EasyCorp/EasyAdminBundle/blob/15c4125818b738785920c87029048ebf31e3b45c/src/Resources/views/crud/edit.html.twig#L61
And so, if you want to change how a field renders, you should create a custom form theme for this. I actually answered a similar question recently (honestly, I should have covered this in the tutorial) https://symfonycasts.com/screencast/easyadminbundle/association-many#comment-28419
The process is basically:
A) Use the web debug toolbar to find the name of the block(s) you can use to override how this one field renders
B) Create a template and render the field (and blocks) inside. This is probably the hardest part and has nothing to do with EasyAdmin - it is 100% about learning how to render a field in a custom way via a form theme https://symfony.com/doc/current/form/form_themes.html and https://symfonycasts.com/screencast/symfony-forms/form-theme-create
C) Call ->setFormTheme()
on your field as an easy way to make sure your new template is included when the field is rendered.
Let me know if this helps!
Cheers!
Got it!!!
Thanks a lot this amazing content, honestly I'v never enjoyed any course as much as I do in SymfonyCasts, It's super useful, full of actually important tips and simply fun! I really appreciate the content thx 🤩
// composer.json
{
"require": {
"php": ">=8.1.0",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"doctrine/doctrine-bundle": "^2.1", // 2.5.5
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.2.1
"doctrine/orm": "^2.7", // 2.10.4
"easycorp/easyadmin-bundle": "^4.0", // v4.0.2
"handcraftedinthealps/goodby-csv": "^1.4", // 1.4.0
"knplabs/knp-markdown-bundle": "dev-symfony6", // dev-symfony6
"knplabs/knp-time-bundle": "^1.11", // 1.17.0
"sensio/framework-extra-bundle": "^6.0", // v6.2.5
"stof/doctrine-extensions-bundle": "^1.4", // v1.7.0
"symfony/asset": "6.0.*", // v6.0.1
"symfony/console": "6.0.*", // v6.0.2
"symfony/dotenv": "6.0.*", // v6.0.2
"symfony/flex": "^2.0.0", // v2.0.1
"symfony/framework-bundle": "6.0.*", // v6.0.2
"symfony/mime": "6.0.*", // v6.0.2
"symfony/monolog-bundle": "^3.0", // v3.7.1
"symfony/runtime": "6.0.*", // v6.0.0
"symfony/security-bundle": "6.0.*", // v6.0.2
"symfony/stopwatch": "6.0.*", // v6.0.0
"symfony/twig-bundle": "6.0.*", // v6.0.1
"symfony/ux-chartjs": "^2.0", // v2.0.1
"symfony/webpack-encore-bundle": "^1.7", // v1.13.2
"symfony/yaml": "6.0.*", // v6.0.2
"twig/extra-bundle": "^2.12|^3.0", // v3.3.7
"twig/twig": "^2.12|^3.0" // v3.3.7
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.1
"symfony/debug-bundle": "6.0.*", // v6.0.2
"symfony/maker-bundle": "^1.15", // v1.36.4
"symfony/var-dumper": "6.0.*", // v6.0.2
"symfony/web-profiler-bundle": "6.0.*", // v6.0.2
"zenstruck/foundry": "^1.1" // v1.16.0
}
}
The same error :(