Controlling the "Formatted Value"
Keep on Learning!
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 SubscribeHead back to the index page. One of the nice things about the ImageField
is that you can click to see a bigger version of it. But let's pretend that we don't want that for some reason... like because these are meant to be tiny avatars.
Actually, EasyAdmin has a field that's made specifically for avatars. It's called AvatarField
!
Back in our code, yield AvatarField::new()
and pass it avatar
:
// ... lines 1 - 6 | |
use EasyCorp\Bundle\EasyAdminBundle\Field\AvatarField; | |
// ... lines 8 - 16 | |
class UserCrudController extends AbstractCrudController | |
{ | |
// ... lines 19 - 23 | |
public function configureFields(string $pageName): iterable | |
{ | |
// ... lines 26 - 27 | |
yield AvatarField::new('avatar'); | |
// ... lines 29 - 50 | |
} | |
} |
Yes, we do temporarily have two fields for avatar
. Go refresh and... the original works, but the AvatarField
is broken!
Inspect the image. Yup! This looks like the same problem as before: it's dumping out the filename instead of the full path to it. To fix this, the ImageField
has a ->setBasePath()
method. Does that method exist on AvatarField
? Apparently not!
Controlling the "Formatted Value"
So let's back up. No matter which field type you use, when a field is ultimately printed onto the page, what's printed is something called the formatted value. For some fields - like text fields - that formatted value is just rendered by itself. But for other fields, it's wrapped inside some markup. For example, if you dug into the template for the AvatarField
- something we'll learn to do soon - you'd find that the formatted value is rendered as the src
attribute of an img
tag.
Anyways, the formatted value is something we can control. Do that by calling ->formatValue()
and passing a callback. I'll use a static function()
that will receive a $value
argument - whatever EasyAdmin would normally render as the formatted $value
- and then our entity: User $user
. Inside, we can return whatever value should be printed inside the src
of the img
. So, return $user->getAvatarUrl()
:
// ... lines 1 - 16 | |
class UserCrudController extends AbstractCrudController | |
{ | |
// ... lines 19 - 23 | |
public function configureFields(string $pageName): iterable | |
{ | |
// ... lines 26 - 27 | |
yield AvatarField::new('avatar') | |
->formatValue(static function ($value, User $user) { | |
return $user->getAvatarUrl(); | |
}); | |
// ... lines 32 - 53 | |
} | |
} |
The static
isn't important... it's just kind of a "cool kid" thing to do if your callback does not need to leverage the $this
variable.
Anyways, go back to your browser and refresh. Yay! We have a nice little avatar! But, if you go the the form for this user, interesting! It only renders one of our avatar fields. This is expected: even though we can display two avatar fields on the index page, we can't have two avatar fields in the form. The second one always wins. And that's fine. We don't actually want two fields... it's just nice to understand why that's happening.
If we deleted the ImageField
and used the AvatarField
on the form, you'd see that the AvatarField
renders as a text input! Not very helpful. Ultimately, we want to use ImageField
on the form and AvatarField
when rendering. And we already know how to do that!
Down here... on ImageField,
add ->onlyOnForms()
. And above, on AvatarField
, do the opposite: ->hideOnForm()
:
// ... lines 1 - 16 | |
class UserCrudController extends AbstractCrudController | |
{ | |
// ... lines 19 - 23 | |
public function configureFields(string $pageName): iterable | |
{ | |
// ... lines 26 - 27 | |
yield AvatarField::new('avatar') | |
// ... lines 29 - 31 | |
->hideOnForm(); | |
yield ImageField::new('avatar') | |
// ... lines 34 - 36 | |
->onlyOnForms(); | |
// ... lines 38 - 55 | |
} | |
} |
This gives us the exact result we want.
Allowing Null in formatValue
Oh, and I almost forgot! In the ->formatValue()
callback, technically the User
argument should be allowed to be null. We'll learn why later when we talk about entity permissions. In a real project, I would make the function look like this:
->formatValue(static function($value, ?User $user) {
return $user?->getAvatarUrl();
})
That has a nullable User
argument and uses a PHP 8 syntax that basically says:
If we have a
User
, then callgetAvatarUrl()
and return that string. But if we don't have a user, skip calling the method and just returnnull
.
I'm actually going to remove this for now... because we'll re-add it later when we hit an error.
Next, I want to customize more fields inside of our admin! In particular, I'm excited to check out the very powerful AssociationField
.
Hello Symfonycast Team!
I have a problem with one issue.
I have created company and user entities. I made an onetoone relationship between them. When adding a company to the database by a logged in user in easyadmin, he does not fill in the user_id field, so I cannot see the company of the user who created it.
How by default, in the user field in the company entity, add the field of the currently logged in user. (user_id). So that at the time of creating the company, I would automatically fill in the user_id field in the database with the person who created the company.
Currently,automatic adding a company to me and the user_id = null field. Should be the id of the user who added it.
Thank you for your work, Regards