【问题标题】:Symfony 3 - how to prevent sql table from duplicate rowsSymfony 3 - 如何防止 sql 表出现重复行
【发布时间】:2017-05-28 16:35:48
【问题描述】:

我正在 Symfony3 中创建 API,我遇到了一种情况,用户可以将游戏添加到他的堆栈中。所以我有一个连接用户 ID 和游戏 ID 的表,但是当我将行添加到 DB 时,可能会出现重复的情况,例如:

我想避免这种情况,但是该怎么做呢?是否有一些类似 symfony3 的方法来防止这种情况?或者我应该在端点中添加一些 if-else 语句并返回一些 JSON 并成功:false?无论如何,我该怎么做?我正在寻找最简单或最有效的方法。

实体的代码如下:

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity
 * @ORM\Table(name="games_on_stacks")
 */
class GamesOnStacks
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;
    /**
     * @ORM\ManyToOne(targetEntity="User")
     *
     */
    private $user;

    /**
     * @return mixed
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @param mixed $user
     */
    public function setUser(User $user)
    {
        $this->user = $user;
    }

    /**
     * @ORM\ManyToOne(targetEntity="Game")
     */
    private $game;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getGame()
    {
        return $this->game;
    }

    /**
     * @param mixed $game
     */
    public function setGame($game)
    {
        $this->game = $game;
    }

}

和 REST 端点:

<?php


namespace AppBundle\Controller;

use AppBundle\Entity\Game;
use AppBundle\Entity\GamesOnStacks;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

class GameController extends Controller
{
    (...)

    /**
     * @Route("/game/{gameId}/add", name="game_add_to_stack")
     */
    public function addToStack($gameId)
    {
        $gameOnStack = new GamesOnStacks(); 
        // db apply
        $em = $this->getDoctrine()->getManager();
        $game = $em->getRepository('AppBundle:Game')
            ->findOneBy(['id' => $gameId]);
        $gameOnStack->setGame($game);
        $user = $em->getRepository('AppBundle:User')
            ->findOneBy(['id' => 1]);
        $gameOnStack->setUser($user);
        $em->persist($gameOnStack);
        $em->flush();
        $arr = array('success' => true);

        return new JsonResponse(json_encode((array)$arr));

    }
}

【问题讨论】:

  • 您可以查找现有的GamesOnStacks 并仅在没有时保存。此外,您可以设置constraint on database level
  • @MateuszSip 好的,但是怎么做呢?我试过:@UniqueEntity( * fields={"user", "game"}, * errorPath="game", * message="This game is already added on this user stack." * )@ORM\Table(name="games_on_stacks") 行下添加,但没有成功。
  • @UniqueEntity 是另一回事,与validator component 有关。我提到的约束需要模式更新/迁移(这是值得的)。您可以同时使用两者(最好在应用程序和数据库级别引入这种验证)或使用存储库方法将@UniqueEntity 替换为手动检查(这更明确,但如果实施正确,则效果相同)。 symfony 文档中的所有内容都有很好的记录,因此请花一些时间阅读,您应该可以轻松解决问题。

标签: php mysql symfony symfony-3.2


【解决方案1】:

UniqueEntity 约束添加到您的实体并使用控制器中的validator service 验证对象:

AppBundle/Entity/GamesOnStacks.php

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity
 * @ORM\Table(name="games_on_stacks")
 *
 * @UniqueEntity( fields={"user", "game"}, errorPath="game", message="This game is already added on this user stack.")
 */
class GamesOnStacks
{
...
}

AppBundle/Controller/GameController

/**
 * @Route("/game/{gameId}/add", name="game_add_to_stack")
 */
public function addToStack($gameId)
{
    $gameOnStack = new GamesOnStacks(); 
    // db apply
    $em = $this->getDoctrine()->getManager();
    $game = $em->getRepository('AppBundle:Game')
        ->findOneBy(['id' => $gameId]);
    $gameOnStack->setGame($game);
    $user = $em->getRepository('AppBundle:User')
        ->findOneBy(['id' => 1]);
    $gameOnStack->setUser($user);

    // validate using the validator service
    $validator = $this->get('validator');
    $errors = $validator->validate($gameOnStack);

    if (count($errors) > 0) {

        // custom error handling, e.g. returning failure jsonreponse, etc.
        $errorsString = (string) $errors;           

    } else {

        $em->persist($gameOnStack);
        $em->flush();
        $arr = array('success' => true);


        return new JsonResponse(json_encode((array)$arr));
    }

}

【讨论】:

  • 谢谢!这正是我想要的。;)我以这种方式创建了错误处理:if (count($errors) &gt; 0) { $errorsString = ''; foreach ($errors as $error) { $errorsString .= $error-&gt;getMessage(); } $errArr = array( 'success' =&gt; false, 'error' =&gt; $errorsString ); return new JsonResponse(json_encode((array)$errArr)); }
猜你喜欢
  • 2021-08-06
  • 2020-08-12
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多