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

Jour 14 : Les Flux

1.4 / Propel
Symfony version
1.2
Language ORM

Hier, vous avez commencé à développer votre première application symfony. Ne vous arrêtez pas maintenant. Car vous en apprendrez davantage sur symfony, essayez d'ajouter de nouvelles fonctionnalités à votre application, l'héberger quelque part, et la partager avec la communauté.

Passons à quelque chose de complètement différent aujourd'hui.

Si vous êtes à la recherche d'un emploi, vous aurez probablement besoin d'être informé dès qu'un nouveau poste est affiché. Parce qu'il n'est pas très pratique de vérifier le site web toutes les heures, nous allons ajouter plusieurs flux d'emploi aujourd'hui pour que nos utilisateurs Jobeet soient mis au courant.

Les formats

Le framework symfony a un support natif pour les formats et les mime-types. Cela signifie que le même modèle et contrôleur peut avoir différents Templates basés sur le format requêté. Le format par défaut est HTML, mais symfony supporte plusieurs autres formats comme txt, js, css, json, xml, rdf, ou atom.

Le format peut être définie en utilisant la méthode setRequestFormat() de l'objet de la requête :

$request->setRequestFormat('xml');

Mais la plupart du temps, le format est incorporé dans l'URL. Dans ce cas, symfony va le mettre pour vous, si la variable spéciale sf_format est utilisé dans la route correspondante. Pour la liste des emplois, l'URL de la liste est :

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

Cette URL est équivalent à :

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

Les deux URL sont équivalentes car les routes générés par la classe sfPropelRouteCollection ont le sf_format comme extension et parce que le HTML est le format par défaut. Vous pouvez le vérifier vous-même en exécutant la tâche app:routes :

Cli

Les flux

Le flux du dernier emploi

Le support de différents formats est aussi facile que la création de Templates différents. Pour créer un flux Atom pour les derniers emplois, créez un Template 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

Les noms des Templates

Comme html est le format le plus couramment utilisé pour les applications web, il peut être omis du nom du Template. Les deux Templates indexSuccess.php et indexSuccess.html.php sont équivalents et symfony utilise le premier qu'il trouve.

Pourquoi les Templates par défaut sont suffixés avec Success ? Une action ne peut retourner une valeur pour indiquer le Template à rendre. Si l'action renvoie rien, il est équivalent au code suivant :

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

Si vous voulez changer le suffixe, retournez simplement autre chose :

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

Comme nous l'avons vu dans la journée précédente, le nom du Template peut également être modifié en utilisant la méthode setTemplate() :

$this->setTemplate('foo');

Par défaut, symfony va changer le Content-Type de la réponse en fonction du format, et pour tous les formats non-HTML, le layout est désactivé. Pour un flux Atom, symfony change le Content-Type en application/atom+xml; charset=utf-8.

Dans le pied de page de Jobeet, mettez à jour le lien vers le flux :

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

L'URI interne est la même que pour la liste job avec le sf_format ajouté comme une variable.

Ajoutez un balise <link> dans la section d'entête du layout pour permettre de découvrir par le navigateur automatiquement notre flux :

<!-- 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) ?>" />

Pour l'attribut href du lien, une URL (Absolue) est utilisée grâce au second argument du helper url_for().

Remplacer l'entête du Template Atom avec le code suivant :

<!-- 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>

Notez l'utilisation du U comme un argument pour getCreatedAt() pour obtenir la date comme un timestamp. Pour obtenir la date du dernier post, créez la méthode getLatestPost() :

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

Les entrées du flux peuvent être générées par le code suivant :

<!-- 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 ?>

La méthode getHost() de l'objet de la requête ($sf_request) retourne l'hôte actuel, qui est très pratique pour créer un lien absolu pour le logo de l'entreprise.

Flux

tip

Lors de la création d'un flux, le débogage est plus facile si vous utilisez des outils en ligne de commande comme curl ou wget, car vous voyez le contenu actuel du flux.

Les derniers emplois dans le flux de la catégorie

L'un des objectifs de Jobeet est d'aider les gens à trouver un emploi plus ciblées. Donc, nous devons fournir un flux pour chaque catégorie.

D'abord, nous allons mettre à jour la route category pour ajouter le support de différents formats :

// 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)

Maintenant, la route category comprend à la fois les formats html et atom. Mettez à jour les flux de la catégorie dans les Templates :

<!-- 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>
 
<!-- 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>

La dernière étape consiste à créer le Template showSuccess.atom.php. Mais comme ce flux sera également la liste des emplois, nous pouvons refactoriser le code qui génère les entrées du flux en créant un partial _list.atom.php. Comme pour le format html, les partials ont un format spécifique :

<!-- apps/frontend/modules/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 ?>

Vous pouvez utiliser le partial _list.atom.php pour simplifier le Template du flux emploi :

<!-- 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>

Enfin, créez le Template 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>

Quant au flux principal des emplois, nous avons besoin de la date du dernier emploi pour une catégorie :

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

Flux de la catégorie

À demain

Comme avec de nombreuses fonctionnalités de symfony, le support du format natif vou permet d'ajouter des flux à vos sites Web sans effort.

Aujourd'hui, nous avons amélioré l'expérience du demandeur d'emploi. Demain, nous allons voir comment assurer une plus grande exposition aux annonceurs en leur fournissant un service Web.