A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

12.6. Crear Entidades

Para el módulo Application, las entidades se guardan (por convención) en la carpeta Entity dentro de la carpeta fuente del módulo. Las clases tipo entidad están en el namespace Application\Entity.

12.6.1. Agregar la Entidad Post

Comenzamos con la creación de la entidad Post. Creamos el archivo Post.php dentro de la carpeta Entity del módulo. (Si aún no hemos creado la carpeta Entity es momento de hacerlo ahora). Colocamos este código dentro del archivo:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * This class represents a single post in a blog.
 * @ORM\Entity
 * @ORM\Table(name="post")
 */
class Post
{
  // Post status constants.
  const STATUS_DRAFT       = 1; // Draft.
  const STATUS_PUBLISHED   = 2; // Published.

  /**
   * @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;

  // Returns ID of this post.
  public function getId()
  {
    return $this->id;
  }

  // Sets ID of this post.
  public function setId($id)
  {
    $this->id = $id;
  }

  // Returns title.
  public function getTitle()
  {
    return $this->title;
  }

  // Sets title.
  public function setTitle($title)
  {
    $this->title = $title;
  }

  // Returns status.
  public function getStatus()
  {
    return $this->status;
  }

  // Sets status.
  public function setStatus($status)
  {
    $this->status = $status;
  }

  // Returns post content.
  public function getContent()
  {
    return $this->content;
  }

  // Sets post content.
  public function setContent($content)
  {
    $this->content = $content;
  }

  // Returns the date when this post was created.
  public function getDateCreated()
  {
    return $this->dateCreated;
  }

  // Sets the date when this post was created.
  public function setDateCreated($dateCreated)
  {
    $this->dateCreated = $dateCreated;
  }
}

En el código de arriba tenemos los siguientes elementos:

Es importante señalar que para las propiedades usamos (por convención) nombres en camel-case (como $dateCreated), mientras que para las columnas usamos nombres "canónicos" (en minúsculas con un guión bajo como separador de palabras, como date_created).

Tabla 12.2. Propiedades de la entidad Post
Propiedad Columna Asociada Descripción
$id id ID únicp de la publicación.
$title title Título de la publicación.
$content content Contenido de la publicación.
$status status Estado (borrador/publicado) de la publicación.
$dateCreated date_created Fecha de creación de la publicación.
Table 12.3. Métodos getter y setter de la entidad Post
Método Descripción
getId() Regresa el ID de la publicación.
setId($id) Coloca el ID de la publicación.
getTitle() Regresa el título.
setTitle($title) Coloca el título.
getStatus() Regresa el estado (borrador/publicado).
setStatus($status) Coloca el estado.
getContent() Regresa el contenido de la publicación.
setContent($content) Coloca el contenido de la publicación.
getDateCreated() Regresa la fecha de creación de la publicación.
setDateCreated() Coloca la fecha de creación de la publicación.

Es importante señalar que los métodos de la clase de tipo entidad no tienen anotaciones. No es necesario que las tenga. Sin embargo, podemos colocar comentarios a los métodos y usar anotaciones de Docblock (pero no las de Doctrine), lo que es altamente recomendable.

12.6.2. Agregar las entidades Comment y Tag

Por analogía con la entidad Post creamos las entidades Comment y Tag en la carpeta Entity. Para hacer esto, primero, creamos el archivo Comment.php y colocamos el siguiente código dentro de él:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * This class represents a comment related to a blog post.
 * @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;

  // Returns ID of this comment.
  public function getId()
  {
    return $this->id;
  }

  // Sets ID of this comment.
  public function setId($id)
  {
    $this->id = $id;
  }

  // Returns comment text.
  public function getContent()
  {
    return $this->content;
  }

  // Sets status.
  public function setContent($content)
  {
    $this->content = $content;
  }

  // Returns author's name.
  public function getAuthor()
  {
    return $this->author;
  }

  // Sets author's name.
  public function setAuthor($author)
  {
    $this->author = $author;
  }

  // Returns the date when this comment was created.
  public function getDateCreated()
  {
    return $this->dateCreated;
  }

  // Sets the date when this comment was created.
  public function setDateCreated($dateCreated)
  {
    $this->dateCreated = $dateCreated;
  }
}

Luego, creamos el archivo Tag.php y colocamos el siguiente código dentro de él:

<?php
namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * This class represents a tag.
 * @ORM\Entity
 * @ORM\Table(name="tag")
 */
class Tag
{
  /**
   * @ORM\Id
   * @ORM\GeneratedValue
   * @ORM\Column(name="id")
   */
  protected $id;

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

  // Returns ID of this tag.
  public function getId()
  {
    return $this->id;
  }

  // Sets ID of this tag.
  public function setId($id)
  {
    $this->id = $id;
  }

  // Returns name.
  public function getName()
  {
    return $this->name;
  }

  // Sets name.
  public function setName($name)
  {
    $this->name = $name;
  }
}

Como las entidades Comment y Tag son análogas a la entidad Post no proveemos una descripción detallada del código de arriba.

Es importante notar que no se creo una entidad para la tabla auxiliar post_tag. Esta tabla se usará indirectamente luego en este capítulo cuando se definan las relaciones entre entidades.

12.6.3. Especificar Relaciones entre Entidades

Ahora es tiempo de usar las anotaciones para definir las relaciones entre entidades. Si recordamos, nosotros tenemos dos relaciones entre nuestras entidades:

En Doctrine para expresar relaciones entre dos entidades agregamos una propiedad privada junto con una anotación de Docblock.

Para conocer más detalles sobre las relaciones entre entidades en Doctrine podemos leer esta página de la documentación de Doctrine.

12.6.3.1. Uno a Muchos/Muchos a Uno

Primero vamos a definir la relación uno-a-muchos entre las entidades Post y Comment. Modificamos el archivo Post.php y agregamos las siguientes líneas:

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

/**
 * This class represents a single post in a blog.
 * @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;

  /**
   * Constructor.
   */
  public function __construct()
  {
    $this->comments = new ArrayCollection();
  }

  /**
   * Returns comments for this post.
   * @return array
   */
  public function getComments()
  {
    return $this->comments;
  }

  /**
   * Adds a new comment to this post.
   * @param $comment
   */
  public function addComment($comment)
  {
    $this->comments[] = $comment;
  }
}

Como podemos ver en el código de arriba se agregó la propiedad $comments (línea 19). Esta propiedad será la colección de comentarios de una determinada publicación.

Se inicializa la propiedad $comments en el constructor de la clase (línea 24-27) y se le asigna una instancia de la clase Doctrine\Common\Collections\ArrayCollection.

Un ArrayCollection de Doctrine es un arreglo de objetos, como un array PHP común, pero con características adicionales de Doctrine. Está implementada en el componente Doctrine\Common.

En las líneas 15-18 agregamos las anotaciones de Doctrine para la propiedad $comments, así Doctrine conoce como conseguir todos los comentarios asociados a la publicación:

El método getComments() (líneas 33-36) permite traer todos los comentarios asociados con la publicación.

Además, agregamos el método addComment() (líneas 42-45) para agregar un nuevo comentario a la publicación. Se puede ver que usamos el operador [] exactamente como un típico arreglo de PHP.

Y vice versa, definimos el otro lado de la relación para esto modificamos la entidad Comment de la siguiente manera:

<?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;

  /*
   * Returns associated post.
   * @return \Application\Entity\Post
   */
  public function getPost()
  {
    return $this->post;
  }

  /**
   * Sets associated post.
   * @param \Application\Entity\Post $post
   */
  public function setPost($post)
  {
    $this->post = $post;
    $post->addComment($this);
  }
}

En el código de arriba agregamos la propiedad privada $post a la clase de tipo entidad. Esta no es una colección sino una instancia de la clase Post, por que un solo comentario pertenece a una sola publicación. Las etiquetas de anotación @ORM\ManyToOne y @ORM\\JoinColumn son análogas a aquellas que explicamos antes.

12.6.3.2. Muchos a Muchos

Ahora vamos a expresar la relación mucho-a-muchos entre las entidades Post y Tag. Para esta relación usamos indirectamente la tabla auxiliar post_tag.

Modificamos la entidad Post de la siguiente manera:

<?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;

  // Constructor.
  public function __construct()
  {
    //...
    $this->tags = new ArrayCollection();
  }

  // Returns tags for this post.
  public function getTags()
  {
    return $this->tags;
  }

  // Adds a new tag to this post.
  public function addTag($tag)
  {
    $this->tags[] = $tag;
  }

  // Removes association between this post and the given tag.
  public function removeTagAssociation($tag)
  {
    $this->tags->removeElement($tag);
  }
}

En el código de arriba se hace lo siguiente:

Finalmente, modificamos la entidad Tag de la siguiente manera:

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

class Tag
{
  // ...

  /**
   * @ORM\ManyToMany(targetEntity="\Application\Entity\Post", mappedBy="tags")
   */
  protected $posts;

  // Constructor.
  public function __construct()
  {
    $this->posts = new ArrayCollection();
  }

  // Returns posts associated with this tag.
  public function getPosts()
  {
    return $this->posts;
  }

  // Adds a post into collection of posts related to this tag.
  public function addPost($post)
  {
    $this->posts[] = $post;
  }
}

En el código de arriba por analogía definimos el otro lado de la relación y los métodos getter/setter para recuperar la colección de publicaciones asociadas con la etiqueta y agregamos las publicaciones asociadas con una etiqueta dada.

12.6.4. Especificar la Ubicación de las Entidad

Para permitir que Doctrine conozca donde encontrar las entidades para nuestra módulo Application (o para otro módulo) agregamos las siguientes líneas dentro de nuestro archivo 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'
                ]
            ]
        ]
    ]
];

Arriba en la línea 2 especificamos el namespace Application. Este debe ser el nombre del módulo actual.

Nótese que usualmente no especificamos namespace en los archivos de configuración, pero en este caso en particular es conveniente hacer esto. Como tenemos un namespace definido podemos usar el comodín __NAMESPACE__.

En la línea 8 tenemos la llave doctrine dentro de la que tenemos la subllave driver. En la línea 13 decimos a Doctrine ORM que nuestras entidades se guardan dentro del directorio Entity del directorio src del módulo.


Top