3

I'm trying to display a nice error message when an integrity constraint error shows up while I try to delete an item.

Instead of having a bad error 500, I just want to display a message like : "You can't delete this because some items are linked to it"

I have been searching for a while but I always find solution on "how to solve this error". I don't won't to solve it, I just want to catch the error, just like a @UniqueEntity annotation with a message argument.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Hugo
  • 1,106
  • 15
  • 25

1 Answers1

5

You can implement an EventListener that listen on the PDOException :

// src/CM/PlatformBundlee/EventListener/PDOExceptionResponseListener.php

namespace CM\PlatformBundle\EventListener;

use Symfony\Component\HttpFoundation\Response;
use Doctrine\DBAL\Driver\PDOException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class PDOExceptionResponseListener
{
    public function __construct(SessionInterface $session) 
    {
        $this->session = $session;
    }

    /**
     * @param GetResponseForExceptionEvent $event
     */
    public function onKernelResponse(GetResponseForExceptionEvent $event)
    {
        $request = $event->getRequest();

        $exception =  $event->getException();
        $message = $exception->getMessage();

        // Listen only on the expected exception
        if (!$exception instanceof PDOException) {
            return;
        }

        // You can make some checks on the message to return a different response depending on the MySQL error given.
        if (strpos($message, 'Integrity constraint violation')) {
            // Add your user-friendly error message
            $this->session->getFlashBag()->add('error', 'PDO Exception :'.$message);   
        }
    }
}

Declare it as a service :

// app/config/services.yml
services:
    acme.kernel.listener.pdo_exception_response_listener:
        class: CM\PlatformBundle\EventListener\PDOExceptionResponseListener
        tags:
            - {name: kernel.event_listener, event: kernel.exception, method: onKernelResponse}
        arguments: 
            session: "@session"

Make your template displaying session messages :

// twig
{% for flashMessage in app.session.flashbag.get('error') %}
    {{ flashMessage }} 
{% endfor %}

EDIT

If you want intercept this error on a specific action, you can do this :

try {
    $em->flush();
} catch (\Exception $e) {
    $errorMessage = $e->getMessage();
    // Add your message in the session
    $this->get(‘session’)->getFlashBag()->add('error', 'PDO Exception :'.$errorMessage);   
}
chalasr
  • 12,971
  • 4
  • 40
  • 82
  • Thanks ! I tried to add this but I have an `Attempted to load class "PDOExceptionResponseListener" from namespace "CM\PlatformBundle\EventListener".` error. I might miss something somewhere. :s – Hugo Feb 22 '16 at 10:29
  • I have edited the code in my answer. Now it uses your namespace, and see the comment about the file location, name it exactly like the class name. But, if you need to do this on only one action, use the short solution in my edit. – chalasr Feb 22 '16 at 10:35
  • Thank you for your help. I've changed everything, thanks for the edit. But I have a doubt with this line : `acme.kernel.listener.exception_listener:` should I keep it like this ? – Hugo Feb 22 '16 at 10:45
  • This line is the identifier of your service. You can change it at your own appreciation. It can be `cm.platform.pdo_exception_response_listener` . You will surely never use it. – chalasr Feb 22 '16 at 10:53
  • Alright I fixed it ! I just called my file "ExceptionResponseListener.php", I didn't notice that you changed it. Now it gets the error but : -It doesn't catch the error (this line doesn't work : `if (!$exception instanceof PDOException) { return; }` ) I don't know why but I will find. -And I have also this error `Attempted to call an undefined method named "get" of class "CM\PlatformBundle\EventListener\PDOExceptionResponseListener".` I will try to fix it by myself. Thank you ! – Hugo Feb 22 '16 at 11:12
  • Sorry, I forget a lot of details . See the changes in the class (added use SessionInterface + constructor + changed `$this->get('session')` to `$this->session`) and in the service declaration (arguments session). Then, if the error is not catched, inspect the exception to know if it's a `PDOException` instance. Otherwise, change `PDOException` to the good, but I'm sure it's the good. I'll edit until you accept the answer :) – chalasr Feb 22 '16 at 11:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104166/discussion-between-hugo-and-chalasr). – Hugo Feb 22 '16 at 11:35