DEV Community

Javier Eguiluz
Javier Eguiluz

Posted on

New in EasyAdmin 5.10

EasyAdmin 5.10 is out with better permission checks on custom actions, confirmation messages per entity, badge styles per field and some fixes for the redesign introduced in EasyAdmin 5.9.

Better Custom Action Permissions

EasyAdmin always checked permissions when running built-in actions (edit, delete, etc.). Custom actions were different because setPermission() and disable() only hid the actions, but didn't check the permissions. This was the documented behavior and not a security issue: you just had to add the permission check yourself in the custom actions.

Before, you had to define the permission in two places:

use App\Entity\Order;
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminRoute;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Symfony\Component\HttpFoundation\Response;

class OrderCrudController extends AbstractCrudController
{
    public function configureActions(Actions $actions): Actions
    {
        $viewInvoice = Action::new('viewInvoice', 'Invoice', 'fa fa-file-invoice')
            ->linkToCrudAction('renderInvoice');

        return $actions
            ->add(Crud::PAGE_DETAIL, $viewInvoice)
            // this only hid the action in the UI...
            ->setPermission('viewInvoice', 'ROLE_FINANCE');
    }

    #[AdminRoute('/{id}/invoice')]
    public function renderInvoice(Order $order): Response
    {
        // ...so you had to also protect the action yourself
        $this->denyAccessUnlessGranted('ROLE_FINANCE');

        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, the permission defined in configureActions() is all you need. If the action is disabled or the user doesn't have its permission, EasyAdmin hides the button and also returns a 403 error when someone opens its URL directly:

#[AdminRoute('/{id}/invoice')]
public function renderInvoice(Order $order): Response
{
    // no permission check needed here

    // ...
}
Enter fullscreen mode Exit fullscreen mode

This works for the actions that run a method of the same CRUD controller, which are the ones created with linkToCrudAction() and the ones that use linkToRoute() with a custom action route of that controller. You don't have to change your code: the checks that you added inside those methods keep working, they are only redundant now.

Confirmation Messages That Depend on the Entity

The askConfirmation() method shows a confirmation modal before running an action. Until now, the confirmation was the same for every row: you could enable it or not, and define one message for all entities.

$archive = Action::new('archive', 'Archive')
    ->linkToCrudAction('archive')
    ->askConfirmation('Are you sure you want to archive this post?');
Enter fullscreen mode Exit fullscreen mode

In EasyAdmin 5.10, thanks to a contribution by phcorp, askConfirmation() also accepts a closure that receives the entity, the same way action labels already do:

use App\Entity\Post;

$archive = Action::new('archive', 'Archive')
    ->linkToCrudAction('archive')
    ->askConfirmation(static fn (Post $post) => $post->isPublished()
        ? sprintf('Visitors will not see "%s" anymore.', $post->getTitle())
        : false
    );
Enter fullscreen mode Exit fullscreen mode

The closure returns one of these values:

  • true: shows the generic confirmation message;
  • false: runs the action without confirmation for this entity;
  • a string or a TranslatableInterface object: shows a custom message. These messages are translated and support the same placeholders as before (%action_name%, %entity_name% and %entity_id%).

This solves two common needs: explain what the action does to that specific entity ("Deleting this category also deletes its 12 posts.") and ask only when it matters (drafts are archived right away, published posts ask first).

Badge Styles per Field

EasyAdmin 5.8 redesigned badges and added Crud::setBadgeVariant() to change the style of all the badges of a dashboard or a CRUD controller. But sometimes you want a different style only for one field: for example, a dot badge for the status and the default light badges for everything else.

That's why the fields that render badges now define their own setBadgeVariant() method:

use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;

yield ChoiceField::new('status')
    ->renderAsBadges(['draft' => 'warning', 'published' => 'success'])
    // possible values: 'light', 'solid', 'outline', 'dot'
    ->setBadgeVariant('dot');
Enter fullscreen mode Exit fullscreen mode

This is the same index page before and after using the dot badge variant only in the status field:

The same index page before and after using the dot badge variant in the status field

The method is available in AssociationField, BooleanField, ChoiceField, CollectionField, CurrencyField, LanguageField and LocaleField. It accepts a string or a case of the BadgeVariant enum (e.g. BadgeVariant::Dot). The field variant wins over the CRUD variant; if you set none of them, badges use light as before.

Flags That Look Good Everywhere

Inside an EasyAdmin backend, flags have small rounded corners and a subtle outline, so flags with white areas (like the flags of Japan or Poland) don't blend into the background. But those styles lived in the CSS of EasyAdmin. If you used <twig:ea:Flag> on other pages of your application, you got the raw flag and had to style it yourself.

In EasyAdmin 5.10, the flag includes its own styles, so it looks the same anywhere without loading any CSS file. There are also two new props, radius and bordered, to configure it:

{# rounded corners and outline (the default) #}
<twig:ea:Flag countryCode="JP"/>

{# possible values: none, sm, md, lg, full #}
<twig:ea:Flag countryCode="JP" radius="md"/>

{# no outline #}
<twig:ea:Flag countryCode="JP" bordered="{{ false }}"/>

{# the original flag, without any style #}
<twig:ea:Flag countryCode="JP" radius="none" bordered="{{ false }}"/>
Enter fullscreen mode Exit fullscreen mode

A Form Field Reference in the UI Kit

The UI Kit is a set of pages inside your own dashboard to see the EasyAdmin components and try designs. In this version it adds a new page at /admin/_ea_ui_kit/form_fields with a form that includes all the form fields that EasyAdmin supports natively: text, editors, choices, dates, numbers, countries, collections, file uploads, etc.

The form field reference page of the UI Kit, with all the form fields of EasyAdmin grouped by type

The page is rendered inside your dashboard, so it uses your theme and your custom CSS. If you change the design of your backend, you can check the result in all the fields on a single page, instead of visiting many CRUD forms. The buttons above the form show the fields with help messages, with validation errors or disabled.

Like the rest of the UI Kit, this page is only available in debug mode, so it doesn't exist in production.

Improved Performance

Most applications that use EasyAdmin are not only a backend: they also have a public website, an API, etc. However, EasyAdmin was building many of its own services on every request of the application, even on pages that have nothing to do with the backend. The reason is that Symfony creates the event listeners and the argument value resolvers before knowing if they are needed, and ours depended on factories, registries and the route generator.

In EasyAdmin 5.10, the admin route subscriber receives a single service locator and only asks for its services after it knows that the request is an EasyAdmin one. The two argument resolvers also have a lower priority, so Symfony resolves the services injected in your controllers before reaching them. You don't have to do anything to get this improvement.


Support EasyAdmin development:

⭐ Upgrade to EasyAdmin Pro for advanced features like Audit Log and Content Lock
❤️ Become a sponsor if EasyAdmin helps your company ship faster

Top comments (0)