Symfony 1.4, la guía definitiva

8.6. Extender el modelo

Los métodos del modelo que se generan automáticamente están muy bien, pero no siempre son suficientes. Si se incluye lógica de negocio propia, es necesario extender el modelo añadiendo nuevos métodos o redefiniendo algunos de los existentes.

8.6.1. Añadir nuevos métodos

Los nuevos métodos se pueden añadir en las clases vacías del modelo que se generan en el directorio lib/model/doctrine. Se emplea $this para invocar a los métodos del objeto actual y self:: para invocar a los métodos estáticos de la clase actual. No se debe olvidar que las clases personalizadas heredan los métodos de las clases Base del directorio lib/model/doctrine/base.

Por ejemplo, en el objeto Articulo generado en el listado 8-3, se puede añadir un método mágico de PHP llamado __toString() de forma que al mostrar un objeto de la clase Articulo se muestre su título, tal y como se indica en el listado 8-20.

Listado 8-20 - Personalizar el modelo, en lib/model/doctrine/Articulo.php

class Articulo extends BaseArticulo
{
  public function __toString()
  {
    return $this->getTitulo();  // getTitulo() se hereda de BaseArticulo
  }
}

También se pueden extender las clases tabla, como por ejemplo para obtener todos los artículos ordenados por fecha de creación, tal y como muestra el listado 8-21.

Listado 8-21 - Personalizando el modelo, en lib/model/doctrine/ArticuloTable.php

class ArticuloTable extends BaseArticuloTable
{
  public static function getTodosOrdenadosPorFecha()
  {
    $q = $this->createQuery('a')
      ->orderBy('a.created_at ASC);

    return $q->execute();
  }
}

Los nuevos métodos están disponibles de la misma forma que los métodos generados automáticamente, tal y como muestra el listado 8-22.

Listado 8-22 - El uso de métodos personalizados del modelo es idéntico al de los métodos generados automáticamente

$articulos = Doctrine_Core::getTable('Articulo')->getTodosOrdenadosPorFecha();
foreach ($articulos as $articulo)
{
  echo $articulo;   // Se llama al método mágico __toString()
}

8.6.2. Redefinir métodos existentes

Si alguno de los métodos generados automáticamente en las clases Base no satisfacen las necesidades de la aplicación, se pueden redefinir en las clases personalizadas. Solamente es necesario mantener el mismo número de argumentos para cada método.

Por ejemplo, el método $articulo->getComentarios() devuelve una colección de objetos Comentario, sin ningún tipo de ordenamiento. Si necesitas los resultados ordenados por fecha de creación siendo el primero el comentario más reciente, puedes crear el método getComentarios(), como muestra el listado 8-23.

Listado 8-23 - Redefiniendo los métodos existentes en el modelo, en lib/model/doctrine/Articulo.php

public function getComentarios()
{
  $q = Doctrine_Core::getTable('Comentario')
        ->createQuery('c')
        ->where('c.articulo_id = ?', $this->getId())
        ->orderBy('c.created_at ASC');

  return $q->execute();
}

8.6.3. Uso de comportamientos en el modelo

Algunas de las modificaciones que se realizan en el modelo son genéricas y por tanto se pueden reutilizar. Por ejemplo, los métodos que hacen que un objeto del modelo sea reordenable o un bloqueo de tipo optimistic para evitar conflictos cuando se guardan de forma concurrente los objetos en la base de datos, se pueden considerar extensiones genéricas que se pueden añadir a muchas clases.

Symfony encapsula estas extensiones en "comportamientos" (del inglés behaviors). Los comportamientos son clases externas que proporcionan métodos extras a las clases del modelo. Las clases del modelo ya están preparadas para ser modificadas por estas clases externas y Symfony se encarga de hacerlo todo de forma transparente.

Para activar los comportamientos en las clases de tu modelo, debes modificar el esquema para hacer uso de la opción actAs:

Articulo:
  actAs: [Timestampable, Sluggable]
  tableName: blog_articulo
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    titulo:   string(255)
    contenido: clob

Después de volver a generar todas las clases del modelo, Articulo tendrá una nueva columna llamada slug, cuyo valor es una versión limpia del título del artículo. Como el slug sólo contiene caracteres muy básicos (no tiene acentos, ni signos de puntuación, ni ñ, ni espacios en blanco, etc.) es ideal para utilizarlo como parte de las URL.

Doctrine incluye varios comportamientos:

  • Timestampable
  • Sluggable
  • SoftDelete
  • Searchable
  • I18n
  • Versionable
  • NestedSet