Mi primer proyecto con Symfony 1.2.7 (parte II)

Symfony LogoEsta artículo es la segunda parte de mis primeros pasos con Symfony, puedes ver la primer parte de como crear un proyecto con Symfony, donde se describe paso a paso como diseñar y generar el proyecto, crear las aplicaciones y los módulos y conectar nuestro proyecto con la base de datos.

En esta segunda parte, vamos a dar forma a la parte pública y privada,  hacer uso del scaffolding para generar las acciones comunes CRUD (Create, Read, Update, Delete) o como tunear las URLs para conseguir un mejor posicionamiento.

Dando forma a la parte privada backend

Generalmente, la parte de administración de cualquier web suele ser una tarea bastante repetitiva y poco agradable de realizar. Para simplificarlo, Symfony dispone de un modulo de Scaffolding que nos facilitará enormemente la tarea, creando el código necesario para hacer las operaciones básicas de creación, lectura, modificación y borrado de registros en base de datos.

Vamos a crear la parte de administración de nuestros dos módulos (posts y comments) con el comando propel:init-admin donde clase es la clase PHP que se encarga de representar la tabla de datos:

symfony propel:init-admin backend post Post
symfony propel:init-admin backend comment Comment

Pues ya tenemos creada las operaciones CRUD de las dos tablas, si visitamos la url http://localhost/blog/post, veremos un listado (de momento vacío) y un botón para crear nuestro primer post. En esta imágen, podemos ver el resultado del listado de posts:

Interfaz de listado de posts

Listado de posts

y en esta otra, el formulario de alta/modificación:

Interfaz de listado de Posts

Edición de Posts

La parte de gestión de comentarios es idéntica a la de los artículos, salvo que en este caso, el formulario de creación del comentario también muestra la clave externa que hace referencia a los artículos. Para mostrar la clave externa, Symfony utiliza el método mágico de PHP llamado __toString().

Si no se ha definido este método, se muestra directamente el valor numérico de id. Si se quiere mostrar el título del post en lugar de su id, tan sólo se debe definir el método mágico __toString() en la clase del modelo de los artículos (en el archivo lib/model/Post.php):

class Post extends BasePost
{
    public function __toString()
    {
        return self::getTitle();
    }
}

Si ahora queremos, añadir un buscador a nuestra página de resultados de comentarios, modificar las columnas que se muestras o el número de resultados por página, lo podemos hacer de una manera simple añadiendo información al archivo generator.yml del módulo de comentarios (/var/www/blog/apps/backend/modules/comment/config/generator.yml).

Añadiendo la siguiente información al archivo:

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Comment
    theme:            default
    list:
      display:        [author, body]
      filters:        [post_id, author, body]
      max_per_page:   5

Conseguimos modificar el número de resultados por página, las columnas mostradas y añadir una caja buscadora:

Symfony Filtrado en comentarios

Filtrado en lista de comentarios

Puedes ver todas las opciones de personalización que nos da el generador aquí.

Nota!! Después de cualquier cambio en un archivo *.yml es necesario que eliminemos la caché de Symfony para ver los resultados por pantalla. Para ello, ejecutamos desde consola symfony cc.

Dando forma a la parte pública frontend

La parte pública, tiene un desarrollo más manual pero aprovecharemos las utilidades que Symfony pone a nuestra disposición para darle forma.

Creamos los modulos del frontend (post y comment) lanzando desde consola la instrucción:

symfony generate:module frontend post
symfony generate:module frontend comment

Si visitamso la dirección http://localhost/blog/post, veremos la página inicial de Symfony. Este módulo, debería mostrar, por ejemplo, un listado de los posts publicados actualmente y al acceder a uno de ellos, mostrar la página de la noticia.

Para crear las acciones de listado y muestra, modificaremos el archivo /var/www/blog/apps/frontend/modules/post/actions/actions.class.php y añadiremos los dos métodos que se encargarán de realizarlas:

class postActions extends sfActions
{
 /**
  * Executes index action
  *
  * @param sfRequest $request A request object
  */
  public function executeIndex(sfWebRequest $request)
  {
    $this->forward('post', 'list');
  }

 /**
  * Executes list posts action
  */
  public function executeList()
  {
  }

 /**
  * Executes show post action
  */
  public function executeShow()
  {
  }
}

Ok, ya le hemos indicado al módulo que dispone de dos acciones más, listar y mostrar, además, le hemos indicado a la acción por defecto ‘index’ que haga una redirección hacia la acción ‘list’, por lo tanto, si visitamos http://localhost/blog/post o http://localhost/blog/post/list obtendremos el mismo resultado.

Llegados a este punto, es interesante explicar como es capaz Symfony de llegar al módulo indicado, la acción correcta y como llama a los templates adecuados. Como habreis deducido, Symfony es capaz de rescatar el módulo y la acción a partir de la URL que escribimos en el navegador, así bien, la URL tiene un formato:

http://dominio.foo/<modulo>/<accion>/<key_var_1>/<value_var_1>/…

Más adelante, veremos que se pueden personalizar las URLs para hacerlas más atractivas a los buscadores, pero por el momento, seguiremos trabajando con los valores por defecto.

Symfony irá a buscar un template html en la carpeta /var/www/blog/apps/frontend/modules/post/templates con el nombre <nombreAccion>+<ResultadoAccion> (en este caso listSuccess.php), parseará las variables y devolverá el resultado por pantalla.

El siguiente paso, será indicar al controlador (post/actions/actions.class.php) que solicite al modelo los posts existentes en base de datos y que se los pase a la vista. El resultado en forma de código sería:

  public function executeList()
  {
    $c = new Criteria();
    $posts = PostPeer::doSelect($c);

    $this->posts = $posts;
  }

Nota!! Todo valor establecido en la variable this de una acción será asignado automáticamente a la vista con el mismo nombre. En este caso, podremos utilizar $posts en el template listSuccess.php.

Ahora vamos a dar forma al template html que muestra el listado de posts. Creamos el archivo listSuccess.php en la carpeta de templates e insertamos esta información:

<?php use_helper('Text') ?>

<h1>Mi Primer Proyecto con Symfony</h1>

<?php foreach($posts as $post): ?>
  <h2><?php echo $post->getTitle() ?></h2>
  <p><?php echo truncate_text($post->getBody(), 200) ?></p>
  <?php echo link_to('Continuar leyendo...', 'post/show/?id='.$post->getId()) ?>
<?php endforeach; ?>

La primera línea se encarga de instanciar el helper Text, que nos permite usar la función truncate_text encargada de recortar el texto a 200 caracteres. También hacemos uso de link_to, disponible sin necesidad de instanciar ningún helper, encargada de crear un enlace con el texto “Continuarl leyendo…”  hacia la dirección indicada en el segundo parámetro.

Una vez tenemos la página de listado de posts, montaremos la que muestra la noticia. Añadiremos la siguiente información al método executeShow de la clase actions.class.php del módulo post:

public function executeShow()
  {
    $id = $this->getRequestParameter('id');
    $post = PostPeer::retrieveByPk($id);

    $this->forward404Unless($post);

    $this->post = $post;
  }

El código recoge el parámetro id pasado por GET y  solicita al modelo el post con el id recogido. Si no existe el post solicitado, mostramos un error 404, en caso contrario, mostraremos la página resultante. El template asociado a esta acción sería:

<h1><?php echo $post->getTitle() ?></h1>

<p><?php echo $post->getExcerpt() ?></p>

<p><?php echo $post->getBody() ?></p>

<?php echo link_to('Volver', 'post/list') ?>

y lo guardaremos con el nombre showSuccess.php en la carpeta de templates.

Modificando la URL por defecto

A peasr de que las URLs que compone Symfony por defecto son bastante semánticas, en este caso, sería interesante que, en lugar del id de post, aparezca el título del mismo por temas de posicionamiento en buscadores.

El enrutameinto se puede definir por aplicación modificando el archivo /var/www/blog/apps/<aplicacion>/config/routing.yml. Por defecto, este archivo contiene unas reglas básicas que modificaremos para dar a la URL el aspecto que deseemos.

Nuestro objetivo es conseguir una url de este estilo:

http://localhost/blog/post/lorem-ipsum-et-dolor/12

Para ello, añadiremos la siguiente entrada al archivo de routing después de el bloque default_index:

show_by_title:
  url:     /post/:title/:id
  param:   { module: post, action: permalink }

Esto, enviará cualquier URL de el estilo definido a la acción permalink que debemos crear en la clase actions.class.php del módulo post:

  /**
   * Executes permalink action
   */
  public function executePermalink()
  {
    $this->forward('post', 'show');
  }

En este caso, nos basta con redireccionar a la acción show ya que en el método que muestra la noticia se recogerá el identificador y pintará los datos. Para más información sobre routing, puedes visitar la guía de Symfony.

Con esto tienes unas priemras nociones para poner en marcha una aplicación, en cualquier caso, puedes aprender más sobre Symfony en la documentación oficial, en el grupo Symfony de Google o en futuros artículos de este blog 😉

6 thoughts on “Mi primer proyecto con Symfony 1.2.7 (parte II)

  1. Muy interesante el artículo, yo también estoy empezando con symfony… lo mejor para mí es el orm y el generador de backends 🙂

  2. La verdad es que el tema del ORM es una pasada… en particular, prefiero Doctrine a Propel, es más completo.

    Por otro lado, como comentas, el generador de backends es un chollo… fácilita enormemente la tarea más pesada y poco agradecida de desarrollar una web.

    Gracias por tu comentario Despai

  3. Hola… buen post…
    Me sale un error al hacer clik en save cuando cargo un post, el error es del explorador:

    “Se ha reiniciado la conexión”
    “La conexión al servidor fue reiniciada mientras la página se cargaba”

    Asi y todo, los registros en la base de datos son dados de alta sin problema. ¿que puede seR?¿

  4. Buen manual, aunque una duda, yo uso doctrine en lugar de propel, y el $c = new Criteria(); no me sirve, tienes alguna otra forma para hacerlo con doctrine?

  5. Hola amigos esta siguiendo este ejemplo de symfony muy bueno… Pero tengo un problema como estoy usando Netbeans 6.9.1 ahi solo trabaja symfony con doctrine y me gustaria saber como hago todo el mismo ejemplo pero con doctrine… Por favor les agradeceria….
    Porque por ejemplo esta parte:
    symfony propel:init-admin backend post Post

    no se como hacer con doctrine……..
    Les agradeceria mucho si me ayudan porfavor…

Comments are closed.