Symfony 实体验证验证外键是否存在
Symfony entity validation verify foreign key exists
我希望能够使用实体验证器约束来验证外键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
首先,您的 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;
我不确定您使用什么代码来获得所有贷款,但正如埃德温所说,这不是很好的形式。你想要更像的东西:
foreach ($loans as $loan) {
$errors = $this->get('validator')->validate($loan);
// do something here if there is an error
}
您编写的断言函数将无法工作,因为您不能将值传递给那里的 isBookLegal()
函数,也不能从您的内部使用数据库 connection/repository实体 class.
如果这里没有更多的上下文,我不太确定你想要完成什么。由于您的 @ORM\OneToOne
注释,Doctrine 已经开始验证您的 $book
成员。您不必执行任何额外的验证。我猜您正试图将一个值直接传递给 $book_id
,这是不正确的。您应该只通过 $loan->setBook(Book $book);
将已经有效的 $book
实体传递给您的 Loan
class
我希望能够使用实体验证器约束来验证外键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
首先,您的 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;
我不确定您使用什么代码来获得所有贷款,但正如埃德温所说,这不是很好的形式。你想要更像的东西:
foreach ($loans as $loan) {
$errors = $this->get('validator')->validate($loan);
// do something here if there is an error
}
您编写的断言函数将无法工作,因为您不能将值传递给那里的 isBookLegal()
函数,也不能从您的内部使用数据库 connection/repository实体 class.
如果这里没有更多的上下文,我不太确定你想要完成什么。由于您的 @ORM\OneToOne
注释,Doctrine 已经开始验证您的 $book
成员。您不必执行任何额外的验证。我猜您正试图将一个值直接传递给 $book_id
,这是不正确的。您应该只通过 $loan->setBook(Book $book);
$book
实体传递给您的 Loan
class