EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

Add a callback method that will give developer the final chance to make updates to each entity action

Open ucscode opened this issue 10 months ago • 4 comments

Short description of what this feature will allow to do:

This will allow devs the final chance to modify each action before they are processed and rendered by easyadmin

Example of how to use this feature

public function configureActions(Actions $actions): Actions
{
    return $actions
        ->modifyActions(function(Action $action, $entity) {
            if ($entity->getId() === 1) {
                $action->setHtmlAttributes([
                    'data-entity' => $entity->getId(),
                ])
                return;
            }
            ...
        });
}

Or something like:

public function configureActions(Actions $actions): Actions
{
    return $actions
        ->modifyIndexRow(function($entity, array|ActionCollection $entityActions) {
            if ($entityActions->has(Action::NEW)) {
                $entityActions->get(Action::NEW)->setHtmlAttributes([
                    'data-entity' => $entity->getId(),
                ])
                return;
            }

            ...
        });
}

ucscode avatar Mar 31 '25 15:03 ucscode

Isn't the existing update action function enough for that? Or are you looking for something more?

                return $actions->update(Crud::PAGE_INDEX, Action::EDIT, function (Action $action) {
                $action->displayIf(function (Foo $foo) {
                    return $foo->getId() === 1;
                });
                return $action;
            });

KDederichs avatar Mar 31 '25 20:03 KDederichs

@KDederichs Unfortunately, the update action is not enough for several reasons.

  1. The purpose of displayIf is to display / hide an action. It is not dedicated for advance logic
  2. The goal is to modify the action dynamically using the entity, not just it's visibility
  3. I tried setting html attributes from within the displayIf method
    $action->displayIf(function(Foo $foo) use ($action) {
        $action->setHtmlAttributes([
            'data-name' => $foo->getName(),
        ])
    })
    
    Unfortunately, it was discarded by easyadmin. It seems easyadmin internally creates a new instance or the method is not being executed at an appropriate time.
  4. The update method itself does not provide access to the entity, you have to think of your way around. Infact, the main objective of this requirement is to have the entity in almost every execution.

Here's an example:

// While creating this action, you literally do not have access to the entity (e.g Foo)

$action = Action::new('myAction')
   ->linkToUrl(function($entity) {
        // great! we can set url based on entity (Foo) parameters
        return 'http://someurl.com/' . $entity->getId();
   })
   ->setHtmlAttribute([
     'entityId' => // sorry, you can't use Foo here
   ]);

In the above case, I linked to a url but cannot set attribute based on the entity associated with the Action. A reasonable solution would be to use update(). However, this also comes with it's own drawback

$actions->update(Crud::PAGE_INDEX, 'myAction', function(Action $action) {
    return $action
        ->setHtmlAttributes([
            'entityId' => // we still do not have entity (Foo), so let's try another work around
        ])
    ;
});

Although we already added linkToUrl at the beginning, however, the $action in the update() method does not contain the url. Thus, throws an exception

Actions must link to either a route, a CRUD action, or a URL. Set the "linkToCrudAction()", "linkToRoute()", or "linkToUrl()" method for the "cancel" action.

So, your solution is a great work around. But, it is also discard.

ucscode avatar Mar 31 '25 21:03 ucscode

Oh no the display if was just an example I grabbed from my code... As you noticed in https://github.com/EasyCorp/EasyAdminBundle/issues/6886 you can't add a callback to attributes. Assuming you COULD though it'd look like this:

                return $actions->update(Crud::PAGE_INDEX, Action::EDIT, function (Action $action) {
                $action->setAttributes(function (entity) {
                    //what ever
                 });
                return $action;

You basically can modify any action as if you'd just create it using $actions->update.

For you to be able to to dynamically edit the attributes though, that's the other issue and has nothing to do with being able to edit existing actions.

KDederichs avatar Apr 01 '25 08:04 KDederichs

@KDederichs Yes I agree with you 100%

However, in cases like this:

->update(Crud::PAGE_INDEX, Action::DELETE, function(Action $action) {
    return $action
        ->setHtmlAttributes([
            'data-bs-target' => '#my-modal',
        ])
    ;
})

The goal now is to use my own custom modal, instead of easyadmin's delete modal. Now aside the fact that setHtmlAttributes does not accept callable and has no entity provided, the data-bs-target does not reflect in the final result. Easyadmin still overrides it with #modal-delete.

So if the changes made are not reflecting, then the update should most likely be considered unsuccessful. Now this does not have to do with callable parameter in setHtmlAttributes, it's the fact that most updates or workarounds are being discarded. Probably because Easyadmin is making some modifications after the updates (haven't really dived deep to understand why).

However, the suggestion proposed here is this, after easyadmin has added and fully configure it's own part, then it can say

Hey, do you have any last changes to make (THAT WILL NOT BE DISCARDED) before I present this to the client?

ucscode avatar Apr 01 '25 08:04 ucscode