Caution: You are browsing the legacy symfony 1.x part of this website.
Cover of the book Symfony 5: The Fast Track

Symfony 5: The Fast Track is the best book to learn modern Symfony development, from zero to production. +300 pages showcasing Symfony with Docker, APIs, queues & async tasks, Webpack, SPAs, etc.

Día once del calendario de symfony: sindicación feed

1.0

Previamente en symfony

La aplicación askeet está lista para ser lanzada en una (prematura) fase beta. De hecho, esto podría seducir a montones de usuarios desde que las características del núcleo (realizar preguntas, leer respuestas, contribuir con nuevas respuestas) son construidas. El problema es que los usuarios habituales encontrarán dificultades para mantenerse al día de los últimos eventos del sitio web askeet. Necesitas proporcionarles noticias frescas sin esfuerzo, y hay un medio para ello: sindicación de noticias. Así que añadamos hoy sindicación de noticias a askeet.

Sindicación de preguntas populares

Enlace a la sindicación en la cabecera

Lo que queremos es un RSS de sindicación de preguntas populares insertado en el <head> del layout global. El HTML resultante debería quedar así:

<link rel="alternate" type="application/rss+xml" title="Popular questions on askeet" href="http://askeet/frontend_dev.php/feed/popular" />

Para hacer esto, abre el layout.php y añade en el <head>:

<?php echo auto_discovery_link_tag('rss', 'feed/popular') ?>

Eso es todo. El helper auto_discovery_link_tag (autocargado con la librería de helper AssetHelper.php) transforma el module/action en una URI de un sitio, pasando por el motor de enrutamiento.

Instalar el plug-in

Symfony proporciona un plug-in sfFeed que automatiza la mayor parte de la generación de sindicaciones. Para instalarlo, usarás la línea de comandos de symfony.

$ symfony plugin-install local symfony/sfFeed

Esto instala las clases del plug-in en el directorio askeet/lib/symfony/plugins/, ya que la opción local le dice a symfony que instale el plug-in solo para la aplicación local. Lo podrías haber instalado para todos tus proyectos cambiando local por global.

Si quieres aprender más sobre plug-ins, sobre cómo extienden el framework y cómo puedes empaquetar las características que usas en varios proyectos en un plug-in, lee el capítulo sobre plug-in del libro de symfony.

No olvides limpiar la caché ya que la carpeta lib/ del proyecto fue modificado a causa del plug-in. A propósito, si experimentas problemas con el comando plugin-install (lo cual probablemente pasará si no usas una versión de instalación de symfony vía PEAR), copia los archivos situados en el directorio lib/plugins/symfony/plugins/sfFeed/ desde el repositorio SVN.

Hablaremos sobre esta clase sfFeed más tarde. Pero primero, necesitamos escribir unas pocas líneas de código.

Crear la acción

La sindicación apunta a la acción popular del módulo feed. Para crearlo, escribe:

$ symfony init-module frontend feed

Luego edita askeet/apps/frontend/modules/feed/actions/action.class.php y añade el siguiente método:

public function executePopular()
{
  // questions
  $c = new Criteria();
  $c->addDescendingOrderByColumn(QuestionPeer::INTERESTED_USERS);
  $c->setLimit(sfConfig::get('app_feed_max'));
  $questions = QuestionPeer::doSelectJoinUser($c);
 
  $feed = sfFeed::newInstance('w');
 
  // channel
  $feed->setTitle('Popular questions on askeet');
  $feed->setLink('@homepage');
  $feed->setDescription('A list of the most popular questions asked on the askeet site, rated by the community.');
 
  // items
  $feed->setFeedItemsRouteName('@question');
  $feed->setItems($questions);
 
  $this->feed = $feed;
}

Define el parámetro personalizado app_feed_max_question en tu archivo de configuración askeet/apps/frontend/config/app.yml:

all:
  feed:
    max: 10

Cambiar la configuración de la vista

Por defecto, el resultado de nuestra acción feed/popular será decorada por el layout, y tendrá un content-type text/html. Eso no es lo que queremos. Así que crea un view.yml en el directorio askeet/apps/frontend/modules/feed/config/ con el contenido:

all:
  has_layout: off
  template:   feed

Esto desactiva el decorador y fuerza que la plantilla de salida sea feedSuccess.php, sea cual sea la acción.

Escribir la plantilla

Eso es porque la plantilla es muy simple y puede ser rehusada por otras sindicaciones. Tan solo escribe esta simple plantilla askeet/apps/frontend/modules/feed/templates/feedSuccess.php:

<?php echo $feed->getFeed() ?>

Testearlo

Ahora vacía la caché (ya que la configuración ha cambiado), actualiza cualquier página del sitio, y date cuenta del icono de sindicación de tu navegador web preferido. Comprueba la sindicación solicitando manualmente:

http://askeet/feed/popular

El resultado es:

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
  <title>Popular questions on askeet</title>
  <link>http://askeet/frontend_dev.php/</link>
  <description>A list of the most popular questions asked on the askeet site, rated by the community.</description>
  <language>en</language>
<item>
 
  <title>What can I offer to my step mother?</title>
  <description>My stepmother has everything a stepmother is usually offered
(watch, vacuum cleaner, earrings, [del.icio.us](http://del.icio.us) account).
Her birthday comes next week, I am broke, and I know that
if I don't offer her something *sweet*, my girlfriend
won't look at me in the eyes for another month.</description>
  <link>http://askeet/frontend_dev.php/question/what-can-i-offer-to-my-step-mother</link>
  <guid>11</guid>
  <pubDate>Sat, 10 Dec 2005 09:44:11 +0100</pubDate>
</item>
<item>
 
  <title>What shall I do tonight with my girlfriend?</title>
  <description>We shall meet in front of the __Dunkin'Donuts__ before dinner,
and I haven't the slightest idea of what I can do with her.
She's not interested in _programming_, _space opera movies_ nor _insects_.
She's kinda cute, so I __really__ need to find something
that will keep her to my side for another evening.</description>
  <link>http://askeet/frontend_dev.php/question/what-shall-i-do-tonight-with-my-girlfriend</link>
  <guid>10</guid>
  <author>[email protected] (Fabien Potencier)</author>
  <pubDate>Sat, 10 Dec 2005 09:44:11 +0100</pubDate>
 
</item>
<item>
  <title>How can I generate traffic to my blog?</title>
  <description>I have a very swell blog that talks
about my class and mates and pets and favorite movies.</description>
  <link>http://askeet/frontend_dev.php/question/how-can-i-generate-traffic-to-my-blog</link>
  <guid>12</guid>
  <author>[email protected] (François Zaninotto)</author>
 
  <pubDate>Sat, 10 Dec 2005 09:44:12 +0100</pubDate>
</item>
  </channel>
</rss>

¿Es rápido?

La magia

Ahora deberías decir: ¿cómo supo symfony dónde encontrar al autor de la pregunta, su e-mail, y cómo adivinó symfony la URI del detalle de una pregunta? La respuesta es: magia.

Si no crees en la magia, entonces vayamos tras la cortina y conozcamos la clase sfFeed. Esta clase puede interpretar los nombres de los métodos del objeto que es pasado como parámetro a sus métodos ->setItems(). El objeto Question tiene un método ->getUser(), así que es usado para encontrar al autor de una pregunta. El objeto User tiene un método ->getEmail() , así que éste también es usado para determinar el e-mail del autor. Y el nombre de la regla pasado al método ->setFeedItemsRouteName() es:

question:
  url:   /question/:stripped_title
  param: { module: question, action: show }

Esto contiene un parámetro stripped_title, así que el método ->getStrippedTitle() del objeto Question es llamado para determinar la URI de la pregunta.

Todo eso sucede porque los nombres del método getter tienen sentido - y la clase sfFeed entiende los objetos diseñados de esa forma. Los mecanismo de interferencia de esta clase son descritos en detalle en el capítulo sobre sindicación del libro de symfony - recurre a él para ver cómo solicitar, por ejemplo, una sindicación sin direcciones de e-mail incluso si un método ->getEmail() existe para el autor del objeto.

note

La vista de la sindicación tiene un content-type XML, así que symfony será suficientemente inteligente para no añadir la barra de herramientas de depuración web a ella (de otro modo el XML no sería válido). Si alguna vez necesitas deshabilitar la barra de herramientas de depuración web manualmente, siempre puedes llamar a:

   sfConfig::set('sf_web_debug', false);

(encuentra más sobre la barra de herramientas de depuración web en el capítulo de depuración del libro de symfony).

Mejoras de la interfaz

Enrutamiento

La URL de una sindicación es tan importante como una normal, así que añade lo siguiente al routing.yml:

# feeds
feed_popular_questions:
  url:   /feed/popular
  param: { module: feed, action: popular }

Imagen RSS

Siempre que un enlace a una lista tenga un campo correspondiente, a bonito icono RSS es mostrado, junto con un link al RSS. Como esto sucederá unas cuantas veces, crea una función link_to_feed() en GlobalHelper.php:

function link_to_feed($name, $uri)
{
  return link_to(image_tag('feed.gif', array('alt' => $name, 'title' => $name, 'align' => 'absmiddle')), $uri);
}

Encontrarás la imagen feed.gif en el repositorio SVN.

Ahora, edita modules/sidebar/templates/defaultSuccess.php así:

<li><?php echo link_to('popular questions', '@popular_questions') ?> <?php echo link_to_rss('popular questions', '@feed_popular_questions') ?></li>

Nos vemos mañana

Este tutorial fue preparado para durar una hora, y solo han pasado 15 minutos. ¿Te has aburrido? No. Esa es otra lección de la programación ágil: si encuentras una solución muy simple a tu problema, es probablemente la correcta. No hay necesidad de pasar demasiado tiempo desarrollando una característica si ya funciona. Y ahora sabes que solo 15 minutos son necesarios para montar, testear y lanzar una sindicación RSS. Después de todo, symfony ofrece herramientas web profesionales para perezosos, así que disfruta de tu tiempo libre y deja el ordenador por hoy.

Si quieres más symfony, intenta hacer una nueva sindicación para las últimas preguntas, las últimas respuestas en general, y las últimas respuestas a una pregunta en concreto. Esto no debería llevarte más de otros 15 minutos, así que tendrás tiempo de descargar el código completo desde el repositorio SVN de askeet, etiquetado como release_day_11, y comprobar si lo has hecho bien. Cuidado porque hay una dificultad oculta - presta atención a la regla de enrutamiento usada para la sindicación de los últimos comentarios.

Y si aún tienes unos cuantos minutos más, ve al foro de askeet y exprésate.

Mañana, enviaremos e-mails con symfony, porque estamos seguros de que nuestros usuarios olvidarán sus claves de acceso. Hasta entonces, duerme profundamente.