Utilizar Traits en la doctrina de entidades

Utilizar Traits en la doctrina de entidades

A partir de PHP 5.4.0, PHP soporta una buena manera para la reutilización de código llamada "Traits", un conjunto de métodos que se pueden incluir dentro de otra clase con el fin de no repetirse. 

A continuación mostramos cómo se pueden utilizar con Doctrinas ORM en un entorno Symfony.

Fundamentos Trait

<?php
trait ExampleTrait {
    public function sayHello() {
        echo "Hello";
    }
}
class A {
    use ExampleTrait;
}
class B {
    use ExampleTrait;
}
$one = new A();
$one->sayHello();    /* return `Hello` */
$two = new B();
$two->sayHello();    /* return `Hello`, too */

 

Un método básico como sayHello () se declara dentro de un Trait  implementado por ambos clases A y B  con un use. Con este sencillo ejemplo puedes ver los fundamentos básicos para el trabajo con Trait.

Si estás interesado en Trait, recomendamos que leas la documentación oficial
También es importante conocer la diferencia entre Traits e Interfaces . He aquí una explicación:

Una interfaz es una afirmación que dice que "este objeto es capaz de hacer tal cosa", mientras que un trait está dando al objeto la capacidad de hacer esa cosa.

Cuando se trata de la organización de la propia arquitectura de la base de datos, no es raro que haya que hacer frente a la duplicación de código. A modo de ejemplo, supongamos que tenemos que desarrollar la aplicación habitual para un blog. En algún momento, es probable que vayamos a crear una entidad básica article y probablemente una entidad comment también.

Ambas entidades se beneficiarían de tener los campos created_at y updated_at (para que podamos ordenar los resultados en esas columnas más adelante). Pero antes de profundizar en Trait, vamos a ver cómo podemos construir esas entidades en Doctrina sin ellos.

Paso 1: crear las entidades

Entidad Article

<?php
namespace BlogAppBundleEntity;
use DoctrineORMMapping as ORM;
/**
 * @ORMTable(name="article")
 * @ORMEntity(repositoryClass="BlogAppBundleEntityArticleRepository")
 */
class Article>
{
    /**
     * @ORMColumn(name="idArticle" type="integer")
     * @ORMId()
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;
    /* Other properties you need in your entity: $title, $content, $author...  */
    /** @ORMColumn(name="created_at" type="datetime") */
    private $createdAt;
    /** @ORMColumn(name="updated_at" type="datetime") */
    private $updatedAt;
   /* Getters & Setters */
}
 

Entidad Comment

<?php
namespace BlogAppBundleEntity;
use DoctrineORMMapping as ORM;
 
/**
 * @ORMTable(name="comment")
 * @ORMEntity(repositoryClass="BlogAppBundleEntityCommentRepository")
 */
class Comment
{
    /**
     * @ORMColumn(name="idComment" type="integer")
     * @ORMId()
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;
    /* Other properties you need in your entity */
    /** @ORMColumn(name="created_at" type="datetime") */
    private $createdAt;
    /** @ORMColumn(name="updated_at" type="datetime") */
    private $updatedAt;
    /* Getters & Setters */
}

Las mismas propiedades $createdAt y $updatedAt se incluyen en ambas clases. ¿Es capaz Traits de limpiar ese código?

Paso 2: crear el Trait

<?php
// src/Blog/AppBundle/Entity/Traits/TimestampableTrait.php
namespace BlogAppBundleEntityTraits;
use DoctrineORMMapping as ORM;
trait TimestampableTrait
{
    /**
     * @var datetime $createdAt
     *
     * @ORMColumn(name="created_at", type="datetime")
     */
    private $createdAt;
    /**
     * @var datetime $updatedAt
     *
     * @ORMColumn(name="updated_at", type="datetime")
     */
    private $updatedAt;
    /**
     * Get createdAt
     *
     * @return datetime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }
    /**
     * Set createdAt
     *
     * @param datetime $createdAt
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
        return $this;
    }
    /**
     * Get updatedAt
     *
     * @return datetime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
    /**
     * Set updatedAt
     *
     * @param datetime $updatedAt
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;
        return $this;
    }
}
Este es un archivo Trait al que hemos movido el código inicial duplicado. Tanto createdAt$ y $updatedAt así como todos los métodos asociados están ahora separados de las entidades. Como resultado, será mucho más fácil de utilizar en otro lugar. Recuerda la sección de introducción con la palabra clave use.

Paso 3: refactorizar las entidades

Entidad Article
<?php // src/Blog/AppBundle/Entity/Article.php namespace BlogAppBundleEntity; use DoctrineORMMapping as ORM; use BlogAppBundleEntityTraitsTimestampableTrait; class Article {     use TimestampableTrait;     /**      * @ORMColumn(name="idArticle" type="integer")      * @ORMId()      * @ORMGeneratedValue(strategy="AUTO")      */     private $id;     /* Other properties you need in your entity */     /* Getters & Setters */ }  
Entidad Comment
<?php
// src/Blog/AppBundle/Entity/Comment.php
namespace BlogAppBundleEntity;
use DoctrineORMMapping as ORM;
use BlogAppBundleEntityTraitsTimestampableTrait;
/**
 * @ORMTable(name="comment")
 * @ORMEntity(repositoryClass="BlogAppBundleEntityCommentRepository")
 */
class Comment
{
    use TimestampableTrait;
    /**
     * @ORMColumn(name="idComment" type="integer")
     * @ORMId()
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;
    /* Other properties you need in your entity */
    /* Getters & Setters */
}
Hecho. Vamos a jugar con la línea de comandos. En primer lugar, vamos a crear las entidades de nuestra base de datos:
php app/console doctrine:schema:create

Este comando cedería:
`Article Entity`
 
| idArticle | *All our other fields...* | created_at | updated_at |
|-----------|---------------------------|------------|------------|
 
`Comment Entity`
 
| idComment | *All our other fields...* | created_at | updated_at |
|-----------|---------------------------|------------|------------|
  Ahora, si deseas crear nuevos objetos para estas clases, verás que los dos tienen los métodos comunes disponibles:
<?php
    $article = new Article();
    $article->setUpdatedAt(new Datetime('now'));
 
    $comment = new Comment();
    $comment->setUpdatedAt(new Datetime('now'));
>
Actualmente, en el ámbito de Symfony, muchos paquetes y extensiones tienden a adherirse a esta forma de hacer las cosas.  Traits no es difícil de utilizar. Es una excelente manera de producir código más ligero y más flexible. Ten cuidado de no abusar de el, a veces, es mejor construir una aplicación de clase única.

Comentarios

Sin comentarios
Ha habido un error en el envío
Comentario enviado. Será revisado por la moderación antes de ser publicado.

Deja tu comentario

Tu nombre:
Tu email:
Tu comentario: