Caution: You are browsing the legacy symfony 1.x part of this website.

Día 14: Feeds o Canales

1.4 / Propel
Symfony version
1.2
Language ORM

Ayer, se comenzó a elaborar tu primer aplicación symfony. No te detengas ahora. A medida que aprendas más sobre Symfony, trata de añadir nuevas funciones a tu aplicación, alojala en algún lugar, y compartelo con la comunidad.

Vamos a pasar hoy a algo completamente diferente.

Si estás buscando un puesto de trabajo, es probable que desees ser informado tan pronto como un nuevo puesto de trabajo se ha publicado. Y no es muy conveniente comprobar el sitio web a cada hora. Vamos hoy a añadir feeds (o canales) de varios puestos de trabajo, para mantener a nuestros usuarios Jobeet actualizados.

Formatos

Symfony tiene soporte nativo para los formatos y tipos MIME. Esto significa que el modelo y el controlador pueden tener diferentes plantillas basadas en el formato solicitado. El formato predeterminado es HTML pero Symfony admite varios formatos de serie como ser txt, js, css, json, xml, rdf, o atom.

El formato se puede configurar utilizando el método setRequestFormat() del objeto request:

$request->setRequestFormat('xml');

Pero la mayor parte del tiempo, el formato está incluído en la URL. En este caso, Symfony lo establecerá por tí si la variable especial sf_format se utiliza en la ruta correspondiente. Para la lista de puestos de trabajo (job), la URL es:

http://www.jobeet.com.localhost/frontend_dev.php/job

Esta URL es equivalente a:

http://www.jobeet.com.localhost/frontend_dev.php/job.html

Ambas URL son equivalentes porque las rutas generadas por la clase sfPropelRouteCollection tienen la sf_format como extension. Puedes comprobarlo por tí mismo ejecutando la tarea app:routes:

Cli

Feeds

Feed de los Últimos Puestos de Trabajo

Soportar diferentes formatos es tán fácil como la crear diferentes plantillas. Para crear un feed Atom para los últimos puestos de trabajo, crea una plantilla indexSuccess.atom.php:

<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jobeet</title>
  <subtitle>Latest Jobs</subtitle>
  <link href="" rel="self"/>
  <link href=""/>
  <updated></updated>
  <author><name>Jobeet</name></author>
  <id>Unique Id</id>
 
  <entry>
    <title>Job title</title>
    <link href="" />
    <id>Unique id</id>
    <updated></updated>
    <summary>Job description</summary>
    <author><name>Company</name></author>
  </entry>
</feed>

sidebar

Nombres de las Plantillas

Como html es el formato más utilizado para aplicaciones web, éste puede ser omitido del nombre de la plantilla. Ambas plantillas indexSuccess.php y indexSuccess.html.php son equivalentes y Symfony utiliza la primero que encuentre.

¿Por qué las plantillas predeterminadas tienen el sufijo Success? Una acción puede devolver un valor para indicar que plantilla se mostrará. Si la acción no dice o devuelve nada, eso equivalente al siguiente código:

return sfView::SUCCESS; // == 'Success'

Si deseas cambiar el sufijo, devuelve otra cosa:

return sfView::ERROR; // == 'Error'
 
return 'Foo';

También puedes cambiar el nombre de la plantilla utilizando el método setTemplate():

$this->setTemplate('foo');

Por defecto, Symfony cambiará la respuesta Content-Type de acuerdo con el formato, y para todos los formatos que no sean HTML, el layout es deshabilitado. Para un Atom feed, Symfony cambiará el Content-Type a application/atom+xml; charset=utf-8.

En el pie de página Jobeet, actualiza el enlace para el feed:

<!-- apps/frontend/templates/layout.php -->
<li class="feed">
  <a href="<?php echo url_for('job', array('sf_format' => 'atom')) ?>">Full feed</a>
</li>

El URI interno es el mismo que para la lista job con el sf_format añadido como una variable.

Añade una etiqueta <link> en la sección head del layout:

<!-- apps/frontend/templates/layout.php -->
<link rel="alternate" type="application/atom+xml" title="Latest Jobs"
  href="<?php echo url_for('job', array('sf_format' => 'atom'), true) ?>" />

Para el atributo href del enlace, se utiliza una URL absoluta gracias al segundo argumento del helper url_for().

Vamos a actualizar el header de la plantilla Atom:

<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
<title>Jobeet</title>
<subtitle>Latest Jobs</subtitle>
<link href="<?php echo url_for('job', array('sf_format' => 'atom'), true) ?>" rel="self"/>
<link href="<?php echo url_for('homepage', true) ?>"/>
<updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', JobeetJobPeer::getLatestPost()->getCreatedAt('U')) ?></updated>
<author>
  <name>Jobeet</name>
</author>
<id><?php echo sha1(url_for('job', array('sf_format' => 'atom'), true)) ?></id>

Nota la utilización de U como argumento para getCreatedAt() para obtener la fecha como timestamp. Para obtener la fecha del envío, crea el método getLatestPost():

// lib/model/JobeetJobPeer.php
class JobeetJobPeer extends BaseJobeetJobPeer
{
  static public function getLatestPost()
  {
    $criteria = new Criteria();
    self::addActiveJobsCriteria($criteria);
 
    return JobeetJobPeer::doSelectOne($criteria);
  }
 
  // ...
}

Los items del feed se pueden generar con el siguiente código:

<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
<?php use_helper('Text') ?>
<?php foreach ($categories as $category): ?>
  <?php foreach ($category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')) as $job): ?>
    <entry>
      <title>
        <?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>)
      </title>
      <link href="<?php echo url_for('job_show_user', $job, true) ?>" />
      <id><?php echo sha1($job->getId()) ?></id>
      <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $job->getCreatedAt('U')) ?></updated>
      <summary type="xhtml">
       <div xmlns="http://www.w3.org/1999/xhtml">
         <?php if ($job->getLogo()): ?>
           <div>
             <a href="<?php echo $job->getUrl() ?>">
               <img src="http://<?php echo $sf_request->getHost().'/uploads/jobs/'.$job->getLogo() ?>"
                 alt="<?php echo $job->getCompany() ?> logo" />
             </a>
           </div>
         <?php endif ?>
 
         <div>
           <?php echo simple_format_text($job->getDescription()) ?>
         </div>
 
         <h4>How to apply?</h4>
 
         <p><?php echo $job->getHowToApply() ?></p>
       </div>
      </summary>
      <author>
        <name><?php echo $job->getCompany() ?></name>
      </author>
    </entry>
  <?php endforeach ?>
<?php endforeach ?>

El método getHost() del objeto request ($sf_request) devuelve el actual host, que viene muy bien para crear un vínculo absoluto para el logo de la empresa.

Feed

tip

Cuando se crea un feed, la depuración es más fácil si utiliza herramientas de línea de comandos como curl o wget, ya que puedes ver el contenido real del feed.

El Feed de los Últimos Puestos de Trabajo de una Categoría

Uno de los objetivos de Jobeet es ayudar a la gente a encontrar puestos de trabajo específicos. Por lo tanto, tenemos que proporcionar un feed para cada categoría.

En primer lugar, vamos a actualizar la ruta category para agregar el soporte para diferentes formatos:

// apps/frontend/config/routing.yml
category:
  url:     /category/:slug.:sf_format
  class:   sfPropelRoute
  param:   { module: category, action: show, sf_format: html }
  options: { model: JobeetCategory, type: object }
  requirements:
    sf_format: (?:html|atom)

Ahora, la ruta category comprenderá tanto los formatos html como atom. Actualiza los enlaces de los feeds de la categoría en las plantillas:

<!-- apps/frontend/modules/job/templates/indexSuccess.php -->
<div class="feed">
  <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a>
</div>
 
[php]
<!-- apps/frontend/modules/category/templates/showSuccess.php -->
<div class="feed">
  <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a>
</div>

El último paso es la creación de la plantilla showSuccess.atom.php. Pero como este feed también lista puestos de trabajo, podemos refactorizar el código que genera los items del feed mediante la creación de un partial _list.atom.php. Como el formato html, los partial son de un formato específico:

<!-- apps/frontend/job/templates/_list.atom.php -->
<?php use_helper('Text') ?>
 
<?php foreach ($jobs as $job): ?>
  <entry>
    <title><?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>)</title>
    <link href="<?php echo url_for('job_show_user', $job, true) ?>" />
    <id><?php echo sha1($job->getId()) ?></id>
      <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $job->getCreatedAt('U')) ?></updated>
    <summary type="xhtml">
     <div xmlns="http://www.w3.org/1999/xhtml">
       <?php if ($job->getLogo()): ?>
         <div>
           <a href="<?php echo $job->getUrl() ?>">
             <img src="http://<?php echo $sf_request->getHost().'/uploads/jobs/'.$job->getLogo() ?>"
               alt="<?php echo $job->getCompany() ?> logo" />
           </a>
         </div>
       <?php endif ?>
 
       <div>
         <?php echo simple_format_text($job->getDescription()) ?>
       </div>
 
       <h4>How to apply?</h4>
 
       <p><?php echo $job->getHowToApply() ?></p>
     </div>
    </summary>
    <author>
      <name><?php echo $job->getCompany() ?></name>
    </author>
  </entry>
<?php endforeach ?>

Puedes utilizar el partial _list.atom.php para simplificar la plantilla del feed de los puestos de trabajo:

<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jobeet</title>
  <subtitle>Latest Jobs</subtitle>
  <link href="<?php echo url_for('job', array('sf_format' => 'atom'), true) ?>" rel="self"/>
  <link href="<?php echo url_for('homepage', true) ?>"/>
  <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', JobeetJobPeer::getLatestPost()->getCreatedAt('U')) ?></updated>
  <author>
    <name>Jobeet</name>
  </author>
  <id><?php echo sha1(url_for('job', array('sf_format' => 'atom'), true)) ?></id>
 
<?php foreach ($categories as $category): ?>
  <?php include_partial('job/list', array('jobs' => $category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')))) ?>
<?php endforeach ?>
</feed>

Finalmente, crear la plantilla showSuccess.atom.php:

<!-- apps/frontend/modules/category/templates/showSuccess.atom.php -->
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jobeet (<?php echo $category ?>)</title>
  <subtitle>Latest Jobs</subtitle>
  <link href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom'), true) ?>" rel="self" />
  <link href="<?php echo url_for('category', array('sf_subject' => $category), true) ?>" />
  <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $category->getLatestPost()->getCreatedAt('U')) ?></updated>
  <author>
    <name>Jobeet</name>
  </author>
  <id><?php echo sha1(url_for('category', array('sf_subject' => $category), true)) ?></id>
 
  <?php include_partial('job/list', array('jobs' => $pager->getResults())) ?>
</feed>

Para el feed principal, necesitamos la fecha del último puesto de trabajo para una categoría:

// lib/model/JobeetCategory.php
class JobeetCategory extends BaseJobeetCategory
{
  public function getLatestPost()
  {
    return $this->getActiveJobs(1)->getFirst();
  }
 
  // ...
}

Category Feed

Nos vemos mañana

Al igual que con muchas características Symfony, el soporte de formatos nativos te permite añadir feeds a tus sitios web sin esfuerzo. Hoy, hemos mejorado la experiencia de alquien que busca empleo. Mañana, vamos a ver cómo dar una mayor exposición a los oferentes de empleo mediante el suministro de un servicio Web.

Feedback

tip

Este capítulo ha sido traducido por Roberto Germán Puentes Díaz. Si encuentras algún error que deseas corregir o realizar algún comentario, no dudes en enviarlo por correo a puentesdiaz [arroba] gmail.com