条令实体中的验证注释
Validation annotations in doctrine entities
您好,我有一个 symfony 项目,其中有一个名为 CompanyController 的控制器。
我有根据我通过 POST 方法发送的一些数据保存新公司的功能。
下面我展示这个方法:
/**
* @param Request $request
* @param ValidatorInterface $validator
* @return string|Response
*/
public function store(Request $request, ValidatorInterface $validator) {
$company = new Company();
$company->setName($request->get('name'));
$company->setTaxNumber($request->get('taxNumber'));
$company->setStreet($request->get('street'));
$company->setCity($request->get('postalCode'));
$company->setOfficeId($request->get('officeId'));
$company->setPostalCode($request->get('postalCode'));
$errors = $validator->validate($company);
if(count($errors) > 0) {
/**
* some code
*/
}
/**
* some response
*/
}
在这种方法中,我试图验证来自 POST 响应的数据。我想知道在实体文件中放置用于验证的注释是否是一种好的做法,如下所示:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\CompanyRepository")
*/
class Company
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank
*/
private $name;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $taxNumber;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank
*/
private $street;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $city;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $postalCode;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*
*/
private $officeId;
/**
* @var datetime $created
*
* @ORM\Column(type="datetime")
*/
protected $createdAt;
/**
* @var datetime $updated
*
* @ORM\Column(type="datetime", nullable = true)
*/
protected $updatedAt;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Employee", mappedBy="company")
*/
private $employees;
public function __construct()
{
$this->employees = new ArrayCollection();
}
/**
* Gets triggered only on insert
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->createdAt = new \DateTime("now");
}
/**
* Gets triggered every time on update
* @ORM\PreUpdate
*/
public function onPreUpdate()
{
$this->updatedAt = new \DateTime("now");
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getTaxNumber(): ?string
{
return $this->taxNumber;
}
public function setTaxNumber(string $taxNumber): self
{
$this->taxNumber = $taxNumber;
return $this;
}
public function getStreet(): ?string
{
return $this->street;
}
public function setStreet(?string $street): self
{
$this->street = $street;
return $this;
}
public function getCity(): ?string
{
return $this->city;
}
public function setCity(string $city): self
{
$this->city = $city;
return $this;
}
public function getPostalCode(): ?string
{
return $this->postalCode;
}
public function setPostalCode(string $postalCode): self
{
$this->postalCode = $postalCode;
return $this;
}
public function getOfficeId(): ?string
{
return $this->officeId;
}
public function setOfficeId(string $officeId): self
{
$this->officeId = $officeId;
return $this;
}
/**
* @return Collection|Employee[]
*/
public function getEmployees(): Collection
{
return $this->employees;
}
public function addEmployee(Employee $employee): self
{
if (!$this->employees->contains($employee)) {
$this->employees[] = $employee;
$employee->setCompany($this);
}
return $this;
}
public function removeEmployee(Employee $employee): self
{
if ($this->employees->contains($employee)) {
$this->employees->removeElement($employee);
// set the owning side to null (unless already changed)
if ($employee->getCompany() === $this) {
$employee->setCompany(null);
}
}
return $this;
}
}
这是正确的做法吗?我遇到的第二种方法是将注释放在完全不同的实体文件中。例如:
public function productPostAction(AccessChecker $checker, Request $request, JsonFromDbObjectConverter $converter){
$productRequest = new ProductRequest();
$productRequest->name = $request->get('name');
$productRequest->users = $request->get('users');
$productRequest->llc = (int)$request->get('llc');
$validator = $this->get('validator');
$errors = $validator->validate($productRequest);
if (count($errors) > 0) {
/**
* some code
*/
}
/**
* some response
*/
}
单独实体 class 进行验证:
<?php
namespace CblBundle\Request;
use Symfony\Component\Validator\Constraints as Assert;
class ProductRequest
{
/**
* @var string
*
* @Assert\NotBlank()
*/
public $name;
/**
* @var array
*/
public $users;
/**
* @var int
* @Assert\Type("integer")
*/
public $llc;
/**
* @Assert\IsTrue(message = "Wrong users data!")
*/
public function isUsersTypeOfNullOrArray()
{
return (is_null($this->users) || is_array($this->users));
}
}
实体不应该对输入验证一无所知。这不是他们的工作。我个人从不这样做。还有其他选项 - 前两个选项取决于 FormTypes(如果使用)。
- Defining form validation constraints in formtypes in symfony - 这没关系,但如果你取出你的 FormType class 你的验证规则也会一样,所以它是高度耦合的方法。不建议这个!
- Defining form validation annotations in models in symfony - 这没关系,因为现在有一个验证专用的单独模型 class。 Entity 和 FormType 都不知道验证。只有验证模型知道它,因此它们彼此解耦。即使你去掉 FormType,你仍然可以使用 Symfony Serializer 和 Validator 的验证模型class。下面的例子就是这样做的。
- Validating, serialising and mapping json request to model classes - 这是最终的首选方法。正如我上面提到的,无论您是否使用 FormTypes,我都会选择这个选项。如果你愿意,你可以使用原生的 Symfony Serializer 而不是 JMS。在同一博客中有更多关于此的示例。
您好,我有一个 symfony 项目,其中有一个名为 CompanyController 的控制器。 我有根据我通过 POST 方法发送的一些数据保存新公司的功能。
下面我展示这个方法:
/**
* @param Request $request
* @param ValidatorInterface $validator
* @return string|Response
*/
public function store(Request $request, ValidatorInterface $validator) {
$company = new Company();
$company->setName($request->get('name'));
$company->setTaxNumber($request->get('taxNumber'));
$company->setStreet($request->get('street'));
$company->setCity($request->get('postalCode'));
$company->setOfficeId($request->get('officeId'));
$company->setPostalCode($request->get('postalCode'));
$errors = $validator->validate($company);
if(count($errors) > 0) {
/**
* some code
*/
}
/**
* some response
*/
}
在这种方法中,我试图验证来自 POST 响应的数据。我想知道在实体文件中放置用于验证的注释是否是一种好的做法,如下所示:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\CompanyRepository")
*/
class Company
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank
*/
private $name;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $taxNumber;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank
*/
private $street;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $city;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*/
private $postalCode;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
*
*/
private $officeId;
/**
* @var datetime $created
*
* @ORM\Column(type="datetime")
*/
protected $createdAt;
/**
* @var datetime $updated
*
* @ORM\Column(type="datetime", nullable = true)
*/
protected $updatedAt;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Employee", mappedBy="company")
*/
private $employees;
public function __construct()
{
$this->employees = new ArrayCollection();
}
/**
* Gets triggered only on insert
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->createdAt = new \DateTime("now");
}
/**
* Gets triggered every time on update
* @ORM\PreUpdate
*/
public function onPreUpdate()
{
$this->updatedAt = new \DateTime("now");
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getTaxNumber(): ?string
{
return $this->taxNumber;
}
public function setTaxNumber(string $taxNumber): self
{
$this->taxNumber = $taxNumber;
return $this;
}
public function getStreet(): ?string
{
return $this->street;
}
public function setStreet(?string $street): self
{
$this->street = $street;
return $this;
}
public function getCity(): ?string
{
return $this->city;
}
public function setCity(string $city): self
{
$this->city = $city;
return $this;
}
public function getPostalCode(): ?string
{
return $this->postalCode;
}
public function setPostalCode(string $postalCode): self
{
$this->postalCode = $postalCode;
return $this;
}
public function getOfficeId(): ?string
{
return $this->officeId;
}
public function setOfficeId(string $officeId): self
{
$this->officeId = $officeId;
return $this;
}
/**
* @return Collection|Employee[]
*/
public function getEmployees(): Collection
{
return $this->employees;
}
public function addEmployee(Employee $employee): self
{
if (!$this->employees->contains($employee)) {
$this->employees[] = $employee;
$employee->setCompany($this);
}
return $this;
}
public function removeEmployee(Employee $employee): self
{
if ($this->employees->contains($employee)) {
$this->employees->removeElement($employee);
// set the owning side to null (unless already changed)
if ($employee->getCompany() === $this) {
$employee->setCompany(null);
}
}
return $this;
}
}
这是正确的做法吗?我遇到的第二种方法是将注释放在完全不同的实体文件中。例如:
public function productPostAction(AccessChecker $checker, Request $request, JsonFromDbObjectConverter $converter){
$productRequest = new ProductRequest();
$productRequest->name = $request->get('name');
$productRequest->users = $request->get('users');
$productRequest->llc = (int)$request->get('llc');
$validator = $this->get('validator');
$errors = $validator->validate($productRequest);
if (count($errors) > 0) {
/**
* some code
*/
}
/**
* some response
*/
}
单独实体 class 进行验证:
<?php
namespace CblBundle\Request;
use Symfony\Component\Validator\Constraints as Assert;
class ProductRequest
{
/**
* @var string
*
* @Assert\NotBlank()
*/
public $name;
/**
* @var array
*/
public $users;
/**
* @var int
* @Assert\Type("integer")
*/
public $llc;
/**
* @Assert\IsTrue(message = "Wrong users data!")
*/
public function isUsersTypeOfNullOrArray()
{
return (is_null($this->users) || is_array($this->users));
}
}
实体不应该对输入验证一无所知。这不是他们的工作。我个人从不这样做。还有其他选项 - 前两个选项取决于 FormTypes(如果使用)。
- Defining form validation constraints in formtypes in symfony - 这没关系,但如果你取出你的 FormType class 你的验证规则也会一样,所以它是高度耦合的方法。不建议这个!
- Defining form validation annotations in models in symfony - 这没关系,因为现在有一个验证专用的单独模型 class。 Entity 和 FormType 都不知道验证。只有验证模型知道它,因此它们彼此解耦。即使你去掉 FormType,你仍然可以使用 Symfony Serializer 和 Validator 的验证模型class。下面的例子就是这样做的。
- Validating, serialising and mapping json request to model classes - 这是最终的首选方法。正如我上面提到的,无论您是否使用 FormTypes,我都会选择这个选项。如果你愿意,你可以使用原生的 Symfony Serializer 而不是 JMS。在同一博客中有更多关于此的示例。