Search code examples
symfonysonata-adminsymfony-sonata

SonataAdmin - How to add custom logic before displaying specific actions links


I know we can customize the action links we want in ou view list in our entity admin class thanks to :

$listMapper
    ->addIdentifier('name')
    ->add('minRole')
    ->add('_action', null, [
        'actions' => [
            'show' => [],
            'edit' => [],
            'delete' => []
        ]
    ])
;

or manage the roles thanks to the service : sonata.admin.security.handler.role

In my case I would like to add a domain logic in order to display or not the delete button (it appears in the view list and the edit view).

{% if attribute(object, hasEvents) is defined and not object.hasEvents %}
   # display it
{% endif %}

I don't know how to override the twig templates of Sonata in order to do that. Only two entities are concerned : Event and Post.

EDIT

for the view list I directly override the list__action_delete.html.twig template (I created app/Resources/SonataAdminBundle/views/CRUD/list__action_delete.html.twig) and this is the code (I know it's not the best way...):

{#

The template override the basic one in order to prevent the display of the delete button (in the view list) for the entities
Post and Event. We only display it if they don't have associated activities.

#}
{% if admin.isGranted('DELETE', object) and admin.hasRoute('delete') %}
    {% if not attribute(object, 'isDeleteable') is defined %}
        <a href="{{ admin.generateObjectUrl('delete', object) }}" class="btn btn-sm btn-default delete_link" title="{{ 'action_delete'|trans({}, 'SonataAdminBundle') }}">
            <i class="fa fa-times"></i>
            {{ 'action_delete'|trans({}, 'SonataAdminBundle') }}
        </a>
    {% else %}
        {% if object.isDeleteable %}
            <a href="{{ admin.generateObjectUrl('delete', object) }}" class="btn btn-sm btn-default delete_link" title="{{ 'action_delete'|trans({}, 'SonataAdminBundle') }}">
                <i class="fa fa-times"></i>
                {{ 'action_delete'|trans({}, 'SonataAdminBundle') }}
            </a>
        {% endif %}
    {% endif %}
{% endif %}

Solution

  • I will show you a solution with the edit template as example. You should follow the same approach to search for any other parts / blocks / templates you want to override.

    What you want to do is override / extend the formactions block of the edit template. The block is defined in the base_edit_form.html.twig template of the sonata admin bundle:

    vendor/sonata-project/admin-bundle/Resources/views/CRUD/base_edit_form.html.twig
    

    To override the template there are different approaches. You can use the approach like described in the symfony doc about how to override any part of a bundle or you can use the config options to override the path for some of the sonata templates as described in the docs.

    I recommend to use the latter. Let's say you have an AppBundle and want to use that to override the template. Add these lines to your sonata config section in the app/config/config.yml file:

    sonata_admin:
        templates:
            edit: AppBundle:CRUD:edit.html.twig
    

    Create the file src/AppBundle/Resources/views/CRUD/edit.html.twig and copy the the formactions block from the vendor/sonata-project/admin-bundle/Resources/views/CRUD/base_edit_form.html.twig template into it. Do not forget to extend the base_edit.html.twig template (first line) shipped with sonata bundle:

    {% extends 'SonataAdminBundle:CRUD:base_list.html.twig' %}
    
    {% block formactions %}
        ...
    {% endblock formactions %}
    

    Find the delete button in the formactions block and add your custom if statement of do whatever manipulation you wanted to do.