【问题标题】:Symfony entity validation verify foreign key existsSymfony 实体验证验证外键是否存在
【发布时间】:2017-06-29 13:29:03
【问题描述】:

我希望能够使用实体验证器约束来验证外键 book_id 是否有效,请参见下文:

Book.php

/**
 * Book
 *
 * @ORM\Table("book")
 * @ORM\Entity
 * @ORM\Entity(repositoryClass="AppBundle\Repository\BookRepository")
 */
class Book
{
     /**
      * @var integer
      * @ORM\Column(name="id", type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
      */
     private $id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string")
     * @Assert\Length(
     *     max = 250,
     *     maxMessage = "Name cannot be longer than {{ limit }} characters",
     *     groups={"create","update"}
     * )
     */
    private $name;

    /**
     * @ORM\OneToOne(targetEntity="Loan", mappedBy="book", fetch="LAZY")
     */
    protected $loan;
}

Loan.php

/**
 * Loan
 *
 * @ORM\Table("loan")
 * @ORM\Entity
 * @ORM\Entity(repositoryClass="AppBundle\Repository\LoanRepository")
 */
class Loan
{
     /**
      * @var integer
      * @ORM\Column(name="id", type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
      */
     private $id;

    /**
     * @var integer
     * @ORM\Column(name="book_id", type="integer")
     */
    protected $book_id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string")
     * @Assert\Length(
     *     max = 500,
     *     maxMessage = "Person cannot be longer than {{ limit }} characters",
     *     groups={"create","update"}
     * )
     */
    private $person;

     /**
      * @ORM\OneToOne(targetEntity="Book", inversedBy="loan")
      * @ORM\JoinColumn(name="book_id", referencedColumnName="id")
      */
    protected $book;
}

这是我目前验证贷款实体的方式

    $loan = new Loan();
    $loan->setPerson($person);
    $loan->setBookId($id);

    /** @var ConstraintViolation $error */
    foreach ($this->get('validator')->validate($loan,null,['create'])->getIterator() as $index => $error) {
        $errorMessages[] = $error->getMessage();
    }

我想也许我可以将这样的自定义验证器添加到贷款实体:

/**
 * @Assert\IsTrue(message = "The book does not exist")
 * @return bool
 */
public function isBookLegal(BookRepository $bookRepository)
{
    return !$bookRepository->fetchById($this->book_id);
}

但我最终得到以下异常:

Type error: Too few arguments to function 
AppBundle\Entity\Loan::isBookLegal(), 0 passed and exactly 1 expected

【问题讨论】:

  • 首先将foreach的第一个参数分配给一个变量,然后在foreach中使用它,这很讨厌。其次,当您调用 isBookLegal 时,您调用它时不带参数 - 这就是您收到此消息的原因。
  • 但是当通过验证触发isBookLegal时如何调用它?换句话说,我怎样才能验证将参数传递给这个函数?

标签: symfony validation docker entity


【解决方案1】:

首先,您的Loan 实体中不应同时包含$book_id$book。你应该删除$book_id,这对你的实体关系来说已经足够了。

然后,您只需在$book 上添加@Assert\NotBlank()

use Symfony\Component\Validator\Constraints as Assert;

...

 /**
  * @ORM\OneToOne(targetEntity="Book", inversedBy="loan")
  * @ORM\JoinColumn(name="book_id", referencedColumnName="id")
  * @Assert\NotBlank()
  */
protected $book;

我不确定您使用什么代码来获得所有贷款,但正如 Edwin 所说,这并不是一个很好的形式。你想要更多类似的东西:

foreach ($loans as $loan) {
    $errors = $this->get('validator')->validate($loan);
    // do something here if there is an error
}

您编写的断言函数将不起作用,因为您无法将值传递给那里的 isBookLegal() 函数,也无法在 Entity 类中使​​用数据库连接/存储库。

如果没有更多上下文,我不确定您要完成什么。 Doctrine 首先要验证您的 $book 成员,因为您的 @ORM\OneToOne 注释。您不必执行任何其他验证。我猜你正试图将一个值直接传递给$book_id,这是不正确的。您应该只通过$loan->setBook(Book $book); 将已经有效的$book 实体传递给您的Loan

【讨论】:

  • 感谢您提供详细的答案,我想我想念学说实体关系的工作原理。如果我删除 book_id 我应该在此设置什么名称:@ORM\JoinColumn(name="book_id", referencedColumnName="id")
  • 哦,我想我现在明白了。所以我不需要将 book_id 隐式设置为类属性,因为教义会发现它需要按名称指定添加该列。
  • 没错。也可以在这里查看:symfony.com/doc/current/doctrine/reverse_engineering.html 如果您的数据库已经创建,您可以让 Doctrine 为您自动生成所有实体。
  • 要做的就是检查 book 字段不为空symfony.com/doc/current/reference/constraints/NotBlank.html,OP 想要检查他的数据库中是否存在 book ID
猜你喜欢
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多