A free and open-source book on ZF3 for beginners


12.6. Создание сущностей

Для модуля Application сущности (по общепринятому стандарту) хранятся в каталоге Entity под корневым каталогом модуля. Классы сущностей содержатся в пространстве имен Application\Entity.

12.6.1. Добавление сущности Post

Начнем с создания сущности Post. Создайте файл Post.php под каталогом Entity. (Если вы еще не создали каталог Entity, самое время это сделать.) Поместите в этот файл следующий код:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Этот класс представляет собой пост в блоге.
 * @ORM\Entity
 * @ORM\Table(name="post")
 */
class Post 
{
    // Константы статуса поста.
    const STATUS_DRAFT       = 1; // Черновик.
    const STATUS_PUBLISHED   = 2; // Опубликованный пост.

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id")   
     */
    protected $id;

    /** 
     * @ORM\Column(name="title")  
     */
    protected $title;

    /** 
     * @ORM\Column(name="content")  
     */
    protected $content;

    /** 
     * @ORM\Column(name="status")  
     */
    protected $status;

    /**
     * @ORM\Column(name="date_created")  
     */
    protected $dateCreated;
  
    // Возвращает ID данного поста.
    public function getId() 
    {
        return $this->id;
    }

    // Задает ID данного поста.
    public function setId($id) 
    {
        $this->id = $id;
    }

    // Возвращает заголовок.
    public function getTitle() 
    {
        return $this->title;
    }

    // Задает заголовок.
    public function setTitle($title) 
    {
        $this->title = $title;
    }

    // Возвращает статус.
    public function getStatus() 
    {
        return $this->status;
    }

    // Устанавливает статус.
    public function setStatus($status) 
    {
        $this->status = $status;
    }
    
    // Возвращает содержимое поста.
    public function getContent() 
    {
        return $this->content; 
    }
    
    // Задает содержимое поста.
    public function setContent($content) 
    {
        $this->content = $content;
    }
    
    // Возвращает дату создания данного поста.
    public function getDateCreated() 
    {
        return $this->dateCreated;
    }
    
    // Задает дату создания данного поста.
    public function setDateCreated($dateCreated) 
    {
        $this->dateCreated = $dateCreated;
    }
}

В этом фрагменте кода находятся:

Обратите внимание, что для свойств используется (по общепринятому стандарту) "верблюжий" (camel-case) регистр (например, $dateCreated), в то время как для столбцов БД используются "канонизированные" имена (в нижнем регистре и с нижними подчеркиваниями, разделяющими слова, например, date_created).

Таблица 12.2. Свойства сущности Post
Свойства Сопоставляемый столбец Описание
$id id Уникальный идентификатор данного поста.
$title title Заголовок данного поста.
$content content Содержимое данного поста.
$status status Статус (черновик/опубликован) данного поста.
$dateCreated date_created Дата создания данного поста.
Таблица 12.3. Геттеры и сеттеры сущности Post
Метод Описание
getId() Возвращает ID данного поста.
setId($id) Задает ID данного поста.
getTitle() Возвращает заголовок.
setTitle($title) Задает заголовок.
getStatus() Возвращает статус (черновик/опубликован).
setStatus($status) Устанавливает статус.
getContent() Возвращает содержимое поста.
setContent($content) Задает содержимое поста.
getDateCreated() Возвращает дату создания данного поста.
setDateCreated() Задает дату создания данного поста.

Обратите внимание на то, что мы не помечаем методы класса сущности аннотациями Doctrine. В этом просто нет необходимости. Однако, если хотите, вы можете помечать методы обычными комментариями и аннотациями Docblock не из Doctrine.

12.6.2. Добавление сущностей Comment и Tag

Аналогично сущности Post, далее мы создаем классы сущностей Comment и Tag` в каталоге Entity. Для этого сперва создайте файл Comment.php и поместите в него следующий код:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Этот класс представляет собой комментарий, относящийся к посту блога.
 * @ORM\Entity
 * @ORM\Table(name="comment")
 */
class Comment 
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id")
     * @ORM\GeneratedValue
     */
    protected $id;

    /** 
     * @ORM\Column(name="content")  
     */
    protected $content;

    /** 
     * @ORM\Column(name="author")  
     */
    protected $author;
    
    /** 
     * @ORM\Column(name="date_created")  
     */
    protected $dateCreated;

    // Возвращает ID данного комментария.
    public function getId() 
    {
        return $this->id;
    }

    // Задает ID данного комментария.
    public function setId($id) 
    {
        $this->id = $id;
    } 
    
    // Возвращает текст комментария.
    public function getContent() 
    {
        return $this->content;
    }

    // Устанавливает статус.
    public function setContent($content) 
    {
        $this->content = $content;
    }
    
    // Возвращает имя автора.
    public function getAuthor() 
    {
        return $this->author;
    }

    // Задает имя автора.
    public function setAuthor($author) 
    {
        $this->author = $author;
    }

    // Возвращает дату создания этого комментария.
    public function getDateCreated() 
    {
        return $this->dateCreated;
    }
    
    // Задает дату создания этого комментария.
    public function setDateCreated($dateCreated) 
    {
        $this->dateCreated = $dateCreated;
    }
}

Теперь создайте файл Tag.php и поместите в него следующий код:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Этот класс представляет собой тег.
 * @ORM\Entity
 * @ORM\Table(name="tag")
 */
class Tag 
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id")
     */
    protected $id;

    /** 
     * @ORM\Column(name="name") 
     */
    protected $name;

    // Возвращает ID данного тега.
    public function getId() 
    {
        return $this->id;
    }

    // Задает ID данного тега.
    public function setId($id) 
    {
        $this->id = $id;
    }

    // Возвращает имя.
    public function getName() 
    {
        return $this->name;
    }

    // Задает имя.
    public function setName($name) 
    {
        $this->name = $name;
    }
}

Так как сущности Comment и Tag аналогичны сущности Post, мы не будем разбирать фрагменты кода выше.

Заметьте, мы не создаем сущность для вспомогательной таблицы post_tag. Эта таблица будет косвенно использоваться далее в этой главе при определении отношений между сущностями.

12.6.3. Определение отношений между сущностями

Теперь используем аннотации, чтобы определить отношения между сущностями. Если помните, между нашими сущностями существуют два отношения:

Для задания отношения между двумя сущностями в Doctrine, добавьте private-свойство вместе с аннотацией Docblock.

Детальную информацию об отношениях между сущностями в Doctrine можно прочесть на этой странице документации Doctrine.

12.6.3.1. «Один-ко-многим» и «многие-к-одному»

Первым делом, давайте определим отношение «один-ко-многим» между сущностями Post и Comment. Внесите следующие изменения в файл Post.php:

<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;
use Application\Entity\Comment;

/**
 * Этот класс представляет собой пост в блоге.
 * @ORM\Entity
 * @ORM\Table(name="post")
 */
class Post 
{
    // ...  
  
    /**
     * @ORM\OneToMany(targetEntity="\Application\Entity\Comment", mappedBy="post")
     * @ORM\JoinColumn(name="id", referencedColumnName="post_id")
     */
    protected $comments;
    
    /**
     * Конструктор.
     */
    public function __construct() 
    {
      $this->comments = new ArrayCollection();               
    }
    
    /**
     * Возвращает комментарии для этого поста.
     * @return array
     */
    public function getComments() 
    {
        return $this->comments;
    }
    
    /**
     * Добавляет новый комментарий к этому посту.
     * @param $comment
     */
    public function addComment($comment) 
    {
        $this->comments[] = $comment;
    }
}

Как видите из фрагмента выше, мы добавили свойство $comments (строка 19). Это свойство будет коллекцией комментариев, относящихся к определенному посту.

Мы инициализируем свойство $comments в конструкторе класса (строки 24-27), создав новый экземпляр класса Doctrine\Common\Collections\ArrayCollection.

ArrayCollection в Doctrine - это массив объектов, похожий на обычный массив PHP, но с дополнительными особенностями, необходимыми Doctrine. Он реализован в компоненте Doctrine\Common.

В строках 15-18 мы добавляем аннотации Doctrine к свойству $comments, тем самым сообщая Doctrine, как получать все комментарии к посту:

Метод getComments() (строки 33-36) позволяет получить все комментарии, связанные с постом.

Помимо этого, мы добавили метод addComment() (строки 42-45) для добавления нового комментария к посту. Как видите, мы используем оператор [], точно так же, как и с обычным PHP-массивом.

Затем мы определяем другую часть этого отношения, изменяя сущность Comment следующим образом:

<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;

// ...
class Comment 
{
    /**
     * @ORM\ManyToOne(targetEntity="\Application\Entity\Post", inversedBy="comments")
     * @ORM\JoinColumn(name="post_id", referencedColumnName="id")
     */
    protected $post;
     
    /*
     * Возвращает связанный пост.
     * @return \Application\Entity\Post
     */
    public function getPost() 
    {
        return $this->post;
    }
    
    /**
     * Задает связанный пост.
     * @param \Application\Entity\Post $post
     */
    public function setPost($post) 
    {
        $this->post = $post;
        $post->addComment($this);
    }
}

В этом фрагменте мы добавили private-свойство $post к классу сущности. Это не коллекция, а один экземпляр класса Post, так как один комментарий всегда принадлежит одному посту. Теги аннотаций @ORM\ManyToOne и @ORM\JoinColumn аналогичны тем, что мы рассмотрели выше.

12.6.3.2. «Многие-ко-многим»

Теперь давайте определим отношение между сущностями Post и Tag. Для этого отношения мы косвенно используем вспомогательную таблицу post_tag.

Измените сущность Post следующим образом:

<?php
//...
use Application\Entity\Tag;

//...
class Post 
{
    //...
    
    /**
     * @ORM\ManyToMany(targetEntity="\Application\Entity\Tag", inversedBy="posts")
     * @ORM\JoinTable(name="post_tag",
     *      joinColumns={@ORM\JoinColumn(name="post_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
     *      )
     */
    protected $tags;
    
    // Конструктор.
    public function __construct() 
    { 
        //...  
        $this->tags = new ArrayCollection();        
    }

    // Возвращает теги для данного поста.
    public function getTags() 
    {
        return $this->tags;
    }      
    
    // Добавляет новый тег к данному посту.
    public function addTag($tag) 
    {
        $this->tags[] = $tag;        
    }
    
    // Удаляет связь между этим постом и заданным тегом.
    public function removeTagAssociation($tag) 
    {
        $this->tags->removeElement($tag);
    }
}

В коде выше мы делаем следующее:

После этого измените сущность Tag таким образом:

<?php
//...
use Doctrine\Common\Collections\ArrayCollection;

class Tag 
{
    // ...
  
    /**
     * @ORM\ManyToMany(targetEntity="\Application\Entity\Post", mappedBy="tags")
     */
    protected $posts;
    
    // Конструктор.
    public function __construct() 
    {        
        $this->posts = new ArrayCollection();        
    }
  
    // Возвращает посты, связанные с данным тегом.
    public function getPosts() 
    {
        return $this->posts;
    }
    
    // Добавляет пост в коллекцию постов, связанных с этим тегом.
    public function addPost($post) 
    {
        $this->posts[] = $post;        
    } 
}

В этом фрагменте мы аналогичным образом определяем другую часть отношения, а также геттер и сеттер для извлечения коллекции постов, связанных с тегом, и добавления постов, связанных с заданным тегом.

12.6.4. Указание местонахождений сущностей

Чтобы сообщить Doctrine, где найти сущности для модуля Application (или другого вашего модуля), добавьте следующий код в файл module.config.php:

<?php
namespace Application;

use Doctrine\ORM\Mapping\Driver\AnnotationDriver;

return [
  // ...
  'doctrine' => [
        'driver' => [
            __NAMESPACE__ . '_driver' => [
                'class' => AnnotationDriver::class,
                'cache' => 'array',
                'paths' => [__DIR__ . '/../src/Entity']
            ],
            'orm_default' => [
                'drivers' => [
                    __NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
                ]
            ]
        ]
    ]  
];

В строке 2 данного фрагмента мы указываем пространство имен Application. Это должно быть имя текущего модуля.

Обратите внимание на то, что обычно мы не указываем пространство имен в файлах конфигурации, но в данном случае удобно это сделать. После того, как мы определили пространство имен, мы можем использовать плейсхолдер __NAMESPACE__.

В строке 8 находится ключ doctrine, и под ним подключ driver. В строке 13 мы сообщаем ORM Doctrine, что наши сущности хранятся в каталоге Entity под корневым каталогом модуля src.


Top