Аннотации проверки в сущностях доктрины

Привет, у меня есть проект 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;
    }
}

Это правильный подход? Второй подход, с которым я столкнулся, заключается в том, чтобы поместить аннотацию в совершенно другой файл Entity. Например:

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
                */
}

Отдельный класс Entity для проверки:

<?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));
    }
}
этот ответ относится к вашему вопросу
gp_sflover 01.07.2019 13:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
1
1 538
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сущности не должны ничего знать о проверке ввода. Это не их работа. Я лично никогда так не делаю. Есть и другие варианты — первые два зависят от FormTypes, если они используются.

  1. Определение ограничений проверки формы в типах форм в symfony — это нормально, но если вы уберете свой класс FormType, ваши правила проверки также будут работать, поэтому это сильно связанный подход. Не намекайте на это!
  2. Определение аннотаций проверки формы в моделях в symfony — это нормально, потому что теперь есть отдельный класс модели для проверки. Ни Entity, ни FormType не знают о проверке. Только модель проверки знает об этом, поэтому все отделено друг от друга. Даже если вы уберете FormType, вы все равно сможете использовать класс модели проверки с Symfony Serializer и Validator. Пример ниже делает это.
  3. Проверка, сериализация и сопоставление JSON-запросов с классами моделей — это окончательный и предпочтительный подход. Как я упоминал выше, независимо от того, используете ли вы FormTypes или нет, я бы выбрал этот вариант. Вы можете использовать нативный Symfony Serializer вместо JMS, если хотите. В том же блоге есть и другие примеры.

Я не очень понимаю второй подход. Почему вы разделяете проблемы на сущность и модель? Оба выглядят как POJO, и когда вы пренебрегаете аннотациями ORM, вы удаляете проблему ORM, а когда вы пренебрегаете аннотацией Assert, вы удаляете проблему проверки. Я не вижу смысла в дальнейшем разделении, тем более что вам нужно снова сопоставить эти два элемента в контроллере.

Richard Kiefer 28.06.2021 14:59

Другие вопросы по теме