Я перенес свои сообщения в собственный блог, потому что Medium становится все менее и менее удобным для читателей (платный доступ, невозможность выделить код и т. Д.). Чтобы прочитать эту статью в более приятном и дружественном контексте, прочтите ее в моем личном блоге и подписывайтесь на меня в Twitter, чтобы получать уведомления!

Https://titouangalopin.com/using-traits-to-compose-your-doctrine-entities/

Черты были введены в PHP 5.4 (6 лет назад) как способ составлять классы, не полагаясь на наследование (в отличие от возможности расширять несколько классов, как в C ++). Эта функция PHP уже сама по себе активно используется во многих фреймворках.

Однако есть особый случай, когда черты характера проявляются еще больше: сущности доктрины. В этой быстрой статье (август;)) я хотел бы поговорить о том, как черты могут быть чрезвычайно полезны для создания ваших сущностей Doctrine, особенно при использовании расширений Doctrine.

Использование черт в ваших сущностях

Сущность, являющаяся стандартным классом PHP, вполне может использовать черты для определения дополнительных свойств. Более того, Doctrine может обрабатывать аннотации к свойствам признаков так же, как если бы они были свойствами внутри самой сущности.

Мы можем использовать это для создания многократно используемых частей сущностей. Например, у большинства моих сущностей есть ID и UUID (как я обсуждал в соответствующей статье). Используя трейт, я могу легко поделиться этими двумя полями со всеми своими сущностями:

class Project
{
    use EntityIdTrait;
    // ...
}

trait EntityIdTrait
{
    /**
     * The unique auto incremented primary key.
     *
     * @var int|null
     *
     * @ORM\Id
     * @ORM\Column(type="integer", options={"unsigned": true})
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * The public primary identity key.
     *
     * @var UuidInterface
     *
     * @ORM\Column(type="uuid", unique=true)
     */
    protected $uuid;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getUuid(): UuidInterface
    {
        return $this->uuid;
    }
}

Использование трейтов для удобного использования расширений Doctrine

Расширения Doctrine - это набор расширений, разработанных, чтобы помочь вам с общими задачами, связанными с сущностями, такими как ярлыки, временные метки и т. Д. Используя трейты, можно упростить использование этих расширений.

EntityNameTrait

Например, я создал черту, определяющую общее поле name и связанный с ним slug, который будет автоматически заполняться расширением Sluggable Doctrine. Кроме того, он определяет метод __toString для моих сущностей с использованием имени.

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;

trait EntityNameTrait
{
    /**
     * @var string|null
     *
     * @ORM\Column(length=100)
     *
     * @Assert\NotBlank
     * @Assert\Length(max=100)
     */
    private $name;

    /**
     * @var string|null
     *
     * @Gedmo\Slug(fields={"name"})
     *
     * @ORM\Column(length=100, unique=true)
     */
    private $slug;

    public function __toString()
    {
        return $this->name;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(?string $name): void
    {
        $this->name = $name;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(?string $slug): void
    {
        $this->slug = $slug;
    }
}

EntityTimestampableTrait

В той же идее я создал трейт для использования расширения Doctrine Timestampable для автоматического сохранения даты создания и даты последнего обновления любой сущности.

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

trait EntityTimestampableTrait
{
    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime")
     *
     * @Gedmo\Timestampable(on="create")
     */
    protected $createdAt;

    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime")
     *
     * @Gedmo\Timestampable(on="update")
     */
    protected $updatedAt;

    public function getCreatedAt(): \DateTime
    {
        return $this->createdAt;
    }

    public function getUpdatedAt(): \DateTime
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(\DateTime $updatedAt)
    {
        $this->updatedAt = $updatedAt;
    }
}

EntitySoftDeletableTrait

Наконец, эта черта использует расширение SoftDeletable для хранения в базе данных некоторых важных сущностей, при этом обрабатывая их как скрытые для приложения.

use Doctrine\ORM\Mapping as ORM;

trait EntitySoftDeletableTrait
{
    /**
     * @var \DateTime|null
     *
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $deletedAt;

    public function getDeletedAt(): ?\DateTime
    {
        return $this->deletedAt;
    }

    public function isDeleted(): bool
    {
        return $this->deletedAt instanceof \DateTimeInterface;
    }

    public function recover()
    {
        $this->deletedAt = null;
    }
}

Я обычно не использую другие расширения, поэтому я не создал для них трейт. Однако это довольно просто сделать и может быть чрезвычайно полезно: не сомневайтесь, создайте его самостоятельно :)!

Есть ли у вас отзывы / идеи? Не стесняйтесь комментировать!