Symfony2 fosuserbundle处理/捕获唯一约束违规

时间:2016-02-23 17:10:42

标签: symfony fosuserbundle

我正在使用symfony 2.8和FOSUserBundle。我想允许管理员编辑用户'用户名和电子邮件。如果已经使用了新用户名或电子邮件,则数据库会出错

  

SQLSTATE [23000]:完整性约束违规:1062重复条目

哪个好,但我不知道怎么回复给那些试图改变它的管理员,告诉他们出了什么问题(应用程序的生产版本只会给出错误500)。我想要做的是显示某种类型的错误消息(最好像FOSUserBundle的形式一样)来说明用户名(或电子邮件)。

表格的相关部分在此构建:

    $userManager = $this->get('fos_user.user_manager');

    $user = $userManager->findUserBy(array('id' => $id));

    $form = $this->createFormBuilder()
          ->add('username', TextType::class, array(
              'label' => 'Username',
              'data' => $user->getUsername(),
          ))
          ->add('email', EmailType::class, array(
              'label' => 'Email',
              'data' => $user->getEmail(),
          ))
          ->getForm();

并在此处理数据库:

    if ($form->isSubmitted() and $form->isValid()) {

        // set new username if different
        $newUsername = $form['username']->getData();
        if ($user->getUsername() !== $newUsername) {
            $user->setUsername($newUsername);
        }

        // set new email if different
        $newEmail = $form['email']->getData();
        if ($user->getEmail() !== $newEmail) {
            $user->setEmail($newEmail);
        }

        $userManager->updateUser($user);
    }

我尝试过很多东西,比如设置username_canonical和email_canonical,或者在我的User.php类中添加@UniqueEntity,但是他们没有帮助(这是有道理的,因为错误是正确的 - 我只是可以& #39; t将其翻译成有用的信息。)

1 个答案:

答案 0 :(得分:0)

如果您不想再进行覆盖以进行一些验证,则需要实现一个EventListener,通过监听onKernelResponse事件来捕获您需要的异常。

<强> DBALExceptionResponseListener.php

// src/AcmeBundle/EventListner/DBALExceptionResponseListener.php

<?php

namespace AcmeBundle\EventListener;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Doctrine\DBAL\DBALException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Router\RouterInterface;

class DBALExceptionResponseListener
{
    public function __construct(SessionInterface $session, RouterInterface $router) 
    {
        $this->session = $session;
        $this->router  = $router;
    }

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

        // Maybe some checks on the route
        if ($request->get('_route') !== 'your_route' || $request->headers->get('referer') !== 'your_referer') {
            return;
        }

        // Listen only on the expected exception
        if (!$exception instanceof DBALException) {
            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', 'SQL Error: '.$message);   
        }

        // Create your custom response to avoid the error page.
        $response = new RedirectResponse($this->router->generate('your_route'));

        // Update the Event Response with yours
        $event->setResponse($response);
    }
}

<强> services.yml

# app/config/services.yml

services:
    acme.kernel.listener.dbal_exception_response_listener:
        class: AcmeBundle\EventListener\DBALExceptionResponseListener
        tags:
            - {name: kernel.event_listener, event: kernel.exception, method: onKernelResponse}
        arguments: 
            session: "@session"
            router: "@router"

通过查看Exception::$message,您可以轻松找到导致问题的属性。

最常见的消息包含:

  

... column&#39; propertyname&#39;不能为空...