martes, 2 de septiembre de 2014

Symfony - Día 14: Feeds o Canales

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 txtjscss,jsonxmlrdf, 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 clasesfDoctrineRouteCollection 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>
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 yindexSuccess.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étodosetTemplate():
$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', Doctrine_Core::getTable('JobeetJob')->getLatestPost()->getDateTimeObject('created_at')->format('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 la función strtotime() para obtener la fecha created_at como timestamp. Para obtener la fecha del envío, crea el método getLatestPost():
// lib/model/doctrine/JobeetJobTable.class.php
class JobeetJobTable extends Doctrine_Table
{
  public function getLatestPost()
  {
    $q = Doctrine_Query::create()
      ->from('JobeetJob j');
    $this->addActiveJobsQuery($q);
 
    return $q->fetchOne();
  }
 
  // ...
}
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->getDateTimeObject('created_at')->format('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
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:   sfDoctrineRoute
  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->getDateTimeObject('created_at')->format('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', Doctrine_Core::getTable('JobeetJob')->getLatestPost()->getDateTimeObject('created_at')->format('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()->getDateTimeObject('created_at')->format('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/doctrine/JobeetCategory.class.php
class JobeetCategory extends BaseJobeetCategory
{
  public function getLatestPost()
  {
    return $this->getActiveJobs(1)->getFirst();
  }
 
  // ...
}
Category Feed

Referencia: http://symfony.com/legacy/doc/jobeet/1_4/es/14?orm=Doctrine

No hay comentarios:

Publicar un comentario