为了账号安全,请及时绑定邮箱和手机立即绑定

Doctrine UniqueConstraintViolationException

Doctrine UniqueConstraintViolationException

PHP
catspeake 2022-08-05 09:41:04
我有一个SQLite表,其中包含有关图像的数据。一列是文本字段,其中包含该图像在网站上的显示位置。该字段具有唯一的约束。以下是表定义:positionCREATE TABLE images (id INTEGER PRIMARY KEY, title TEXT UNIQUE NOT NULL, position TEXT UNIQUENOT NULL, caption TEXT, filename TEXT, album INTEGER NOT NULL, publicationDate TEXT, updatedTEXT, createdBy INTEGER NOT NULL, updatedBy INTEGER NOT NULL, FOREIGN KEY (createdBy) REFERENCES users(id), FOREIGN KEY(album) REFERENCES albums(id), FOREIGN KEY (updatedBy) REFERENCES users(id));并且,来自实体的相关位:/*** @ORM\Entity* @ORM\Table(name="images",indexes={*       @Index(name="publication_date", columns={"publicationDate"})},*       uniqueConstraints={@UniqueConstraint(name="unique_position", columns={"position", "fileName"})}*       )*/class Image{    /**    * @ORM\Id    * @ORM\Column(type="integer")    * @ORM\GeneratedValue    **/    protected $id;    /**    * @ORM\Column(type="string", unique=true)    */    protected $position;我可以成功地写入表(Doctrine 保留,然后刷新),除非列上有唯一的约束冲突。当存在唯一的约束冲突时,flush() 将以静默方式失败(不写入数据库),并且应用程序将继续执行。以下是相关代码 - 设置并保留实体后:position        try {            $this->entityManager->flush();            $message['type'] = 'alert-info';            $message['content'] = "$title added succesfully";            return $message;        } catch (UniqueConstraintViolationException $e) {            $message['type'] = 'alert-danger';            $message['content'] = "$title could not be added " . $e;            return $this->create($message, $formVars);        } catch (Exception $e) {            $message['type'] = 'alert-danger';            $message['content'] = "$title could not be added " . $e;            return $this->create($message, $formVars);        }为什么我没有捕捉到异常?或者,它根本没有被扔掉吗?
查看完整描述

1 回答

?
呼唤远方

TA贡献1856条经验 获得超11个赞

发布我上面提供的代码实现提示,只需运行2次即可查看结果,这是控制器:


<?php


namespace App\Controller;


use App\Entity\TestEntity;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\Routing\Annotation\Route;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\Validator\Validator\ValidatorInterface;


class TestController extends AbstractController

{

    /**

     * @Route("/", name="test")

     */

    public function test(Request $request, ValidatorInterface $validator)

    {

        $newEntity = new TestEntity();

        $newEntity->setPosition('test');


        // In addition $form->isValid() does this for you and displays form error specified in entity

        if(($result = $validator->validate($newEntity))->count() === 0) {

            $em = $this->getDoctrine()->getManager();

            $em->persist($newEntity);

            $em->flush();

            dump('Entity persisted');

        } else {

            dump($result); // <- array of violations

            dump('Sorry entity with this position exists');

        }


        die;

    }

}

这是您的实体:


<?php


namespace App\Entity;


use Doctrine\ORM\Mapping as ORM;

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;


/**

 * @ORM\Table(name="test_entity")

 * @ORM\Entity(repositoryClass="App\Repository\TestEntityRepository")

 * 

 * @UniqueEntity(

 *  fields={"position"},

 *  errorPath="position",

 *  message="Duplicate of position {{ value }}."

 * )

 */

class TestEntity

{

    /**

     * @ORM\Column(name="id", type="integer")

     * @ORM\Id

     * @ORM\GeneratedValue(strategy="AUTO")

     */

    private $id;


    public function getId()

    {

        return $this->id;

    }


    /**

     * @ORM\Column(name="position", type="string", length=190, unique=true) // key length limit for Mysql

     */

    private $position;


    public function getPosition()

    {

        return $this->position;

    }


    public function setPosition($position)

    {

        $this->position = $position;

        return $this;

    }

}

出于好奇,我测试了你的第一个想法,它似乎对我有用


<?php


namespace App\Controller;


use App\Entity\TestEntity;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\Routing\Annotation\Route;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\Validator\Validator\ValidatorInterface;


class TestController extends AbstractController

{

    /**

     * @Route("/", name="test")

     */

    public function test(Request $request, ValidatorInterface $validator)

    {

        $newEntity = new TestEntity();

        $newEntity->setPosition('test');


        try {

            $em = $this->getDoctrine()->getManager();

            $em->persist($newEntity);

            $em->flush();

        } catch(\Doctrine\DBAL\Exception\UniqueConstraintViolationException $e) {

            dump('First catch');

            dump($e);

        }

        catch(\Exception $e) {

            dump('Second catch');

            dump($e);

        }


        die;

    }

}

它导致“第一次捕获”的转储,但这可能与我使用的是mysql而不是SQlite有关,这也是对Symfony验证文档的引用,以防您想检查它

EDIT2

Simple Validator 类


class SomeSortOfValidator

{

    public function exists($entity, $fieldName, $fieldValue)

    {

        // Lets suppose you have entity manager autowired.

        $record = $this->em->getRepository($entity)->findOneBy([

            $fieldName => $fieldValue

        ]);

        return $record ? true : false;

    }

}


查看完整回答
反对 回复 2022-08-05
  • 1 回答
  • 0 关注
  • 128 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信