3

How check conditions before remove action and set flash message in sonata-admin?

I do not want remove super-user. My current code:

public function preRemove($object)
    {
        parent::preRemove($object);
        if ($object->getId() === User::SUPER_USER_ID) {
            throw new AccessDeniedException();
        }
    }

Its throw exception. I need send flash message in admin-panel.

Pavel
  • 155
  • 1
  • 7
  • Does this answer your question? [How to set flash message in sonata admin Admin Controller](https://stackoverflow.com/questions/17940448/how-to-set-flash-message-in-sonata-admin-admin-controller) – Cameron Hurd Apr 21 '20 at 13:18
  • @CameronHurd 50/50. I found how set flash message on persist and update action . I dont know, how stop remove action , and set flash message. I want stop remove, redirect back with flash message. – Pavel Apr 21 '20 at 13:23

3 Answers3

1

This is the override function. If you want to stop remove or remove if everything ok you just put parent::preRemove($object); or parent::remove($object); at the end of the function.

public function preRemove($object)
{
    if ($object->getId() === User::SUPER_USER_ID) {
        $this->getRequest()->getSession()->getFlashBag()->add(
            'error',
            'Title, Abstract and Small tile Media are required'
        );
        return;
    }
    //other code to check here

    parent::preRemove($object); 
}

public function remove($object)
{
    if ($object->getId() === User::SUPER_USER_ID) {
        $this->getRequest()->getSession()->getFlashBag()->add(
            'error',
            'Title, Abstract and Small tile Media are required'
        );
        return;
    }
    //other code to check here

    parent::remove($object); 
}
Ryuk Lee
  • 720
  • 5
  • 12
  • If i throw exception, this code not execute. If i not throw exception, i remove my object (i dont want this) – Pavel Apr 28 '20 at 07:27
  • If you throw an exception, it means you expect the code does not execute, right? – Ryuk Lee Apr 28 '20 at 07:30
  • Yes. I want to check the condition. If "ok" - remove the object, otherwise display an error message in the admin panel and not remove object. Now I am throwing an exception ( = http 500 error) P.s. parent::preRemove($object) and parent::remove($object); - empty methods – Pavel Apr 28 '20 at 07:34
  • 1
    use session and return after adding error message. See my update answer – Ryuk Lee Apr 28 '20 at 08:14
  • Thanks! You gave the idea, that i can override "delete" method. – Pavel Apr 28 '20 at 08:27
  • There was a problem. Now two messages are displayed: "success" and "error". Success created after "remove" method and $flashBag->clear() or $flashBag->set('success',null) not work :( – Pavel Apr 28 '20 at 08:37
  • Try to use injection to inject the session bag – Ryuk Lee Apr 28 '20 at 08:41
  • Ryuk Le, i am writed the full answer. Thank You! – Pavel Apr 28 '20 at 10:33
1

Thank you Ryuk Lee, He made me research the code :)

Solution:

public function preRemove($object)
    {
        parent::preRemove($object);
        if ($object->getId() === User::SUPER_USER_ID) {
            $this->getRequest()->getSession()->getFlashBag()->add('sonata_flash_error','Not delete super user');
            throw new ModelManagerException();
        }
    }

ModelManagerException - This is an exception that will make the sonata work properly. Do not delete the object and write a error message in the admin panel, without "success" message. Work only debug = false.

$kernel = new AppKernel('dev', false);

But I met a problem, toogle error messages ("more"):

enter image description here

2 solutions:

1) override template

config.xml

sonata_admin:
    templates:
        layout: 'admin/layout.html.twig'

layout.html.twig

{% extends '@SonataAdmin/standard_layout.html.twig' %}

{% block notice %}
    {% include 'admin/flash_messages.html.twig' %}
{% endblock notice %}

flash_messages.html.twig

{% for type in sonata_flashmessages_types() %}
    {% set domain = domain is defined ? domain : null %}
    {% set messages = sonata_flashmessages_get(type, domain) %}
    {% if messages|length > 0 %}
        {% for message in messages %}
            <div class="alert alert-{{ type|sonata_status_class }} alert-dismissable">
                <button
                        type="button"
                        class="close"
                        data-dismiss="alert"
                        aria-hidden="true"
                        aria-label="{{ 'message_close'|trans({}, 'SonataCoreBundle') }}">
                    &times;
                </button>
                {{ message | raw }}
            </div>
        {% endfor %}
    {% endif %}
{% endfor %}

Result:

enter image description here

2) Override Admin controller.

serivices.yml

admin.user.admin:
    class: AppBundle\Admin\AdminUserAdmin
    arguments: [~, AppBundle\Entity\User, AppBundle\Controller\Admin\AdminUserCRUDController]
    tags:
      - { name: sonata.admin, manager_type: orm, label: 'Admins' }

AdminUserCRUDController

class AdminUserCRUDController extends CRUDController
{
   public function deleteAction($id)
   {
       $redirectResponse = parent::deleteAction($id);
       /** @var FlashBagInterface $flashBag */
       $flashBag = $this->container->get('session')->getFlashBag();
       if($errors = $flashBag->get('sonata_flash_error')){
           $flashBag->set(
               'sonata_flash_error',
               implode('. ',array_unique($errors))
           );
       }
       return $redirectResponse;
   }

Result:

enter image description here

Pavel
  • 155
  • 1
  • 7
0

I have used the CRUD controller preDelete() hook for this.

class MyCrudController extends CRUDController
{
    protected function preDelete(Request $request, $object): ?RedirectResponse
    {
        if (/* some blocking condition */) {
            $this->addFlash(
                'sonata_flash_error',
                $this->trans(
                    'flash_not_allowed_because_of_reasons',
                    ['%name%' => $this->escapeHtml($object)],
                    'SonataAdminBundle'
                )
            );
            return $this->redirectTo($object);
        }

        return null;
    }
}

Within the Sonata Admin CRUD Controller it will run this check:

    $preResponse = $this->preDelete($request, $object);
    if (null !== $preResponse) {
        return $preResponse;
    }

So if you return a Response from your preDelete() method, then Sonata Admin won't continue the delete. And with this method you will have only one flash message.

7ochem
  • 2,183
  • 1
  • 34
  • 42