Prendre un Café

Le weblog de Nicolas Perriault

Aller au contenu | Aller au menu | Aller à la recherche

vendredi 21 mars 2008

En vrac

Edit : Je viens de recevoir 5 invitations pour SlideRocket, une vient de partir chez Xethorn qui l'a demandé en commentaire, les quatres autres seront pour les suivants par ordre d'arrivée :)

vendredi 14 mars 2008

Symfonians en VF

Je viens de mettre en ligne la version française de Symfonians[1]. J'ai préféré utiliser un sous-domaine pour définir la langue courante plutôt qu'un paramètre supplémentaire dans la requête, car le routing de Symfony implique de le gérer pour chacune des route (ou si y'a une astuce, je suis preneur.)

Ici, je détecte le sous domaine et en fait la langue courante de l'utilisateur au moyen d'un filtre. Pour ceux que ça intéresse, en voici le code :

<?php
class i18nSubdomainFilter extends sfFilter
{
  public function execute($filterChain)
  {
    if ($this->isFirstCall())
    {
      $context = $this->getContext();
      $request = $context->getRequest();
      $host_parts = explode('.', $request->getHost());
      if (count($host_parts) > 2) // We have at least a subdomain
      {
        $subdomain = strtolower($host_parts[0]);
        $enabled_cultures = sfConfig::get('app_cultures_enabled', array());
        if (array_key_exists($subdomain, $enabled_cultures))
        {
          sfConfig::set('sf_current_culture', $subdomain);
          $context->getResponse()->addMeta('language', $subdomain, true);
          $context->getUser()->setCulture($subdomain);
        }
      }
    }
    $filterChain->execute();
  }
}

Notez que je définis la liste des langues disponibles dans le fichier app.yml, pour éviter les blagues et gérer les domaines pour chacun des environnements que j'ai configuré[2] :

prod:
  cultures:
    enabled:
      en:    http://symfonians.net/
      fr:    http://fr.symfonians.net/

L'activation du filtre se fait dans le fichier filters.yml :

i18nSubdomain:
  class:    i18nSubdomainFilter

Et roule ma poule, mon routing reste strictement intact :-)

Notes

[1] 690 chaînes à traduire en deux heures, doit sans doûte rester du débris :p

[2] J'ai dautre part une action qui me permet de rediriger l'utilisateur vers la version traduite de la page courante, mais je vous fais grâce du code.

jeudi 13 mars 2008

Symfony 1.1 beta, tour du propriétaire - L'internationalisation (i18n)

Dans la liste des tâches nouvellement ajoutées en Symfony 1.1, on remarque une section dédiée à l'internationalisation :

i18n
  :extract            Extracts i18n strings from php files
  :find               Finds non "i18n ready" strings in an application

Et oui, la fonctionnalité dont tous les gens qui ont un jour travaillé sur des applications internationalisées en Symfony 1.0 ont rêvé a enfin été ajoutée : une tâche d'extraction des chaînes de caractères à traduire, avec génération et mise à jour des fichiers de traductions XLIFF :)

Si vous avez suivi les précédents tutoriels, vous devez disposer d'un projet sf11test, d'une application main et d'un module contact.

On va activer la gestion de l'internationalisation dans l'application en éditant le fichier de configuration apps/main/config/settings.yml comme suit :

[...]
all:
  [...]
  .settings:
    [...]
    i18n:                   on
    [...]
    standard_helpers:       [Partial, Cache, Form, I18N]
    [...]
    default_culture:        en

On part du principe que la langue par défaut sera l'anglais (en). Ajoutons quelques chaînes internationalisées dans le template apps/main/modules/contact/templates/indexSuccess.php au moyen du helper __() :

<h2><?php echo __('Contact us') ?></h2>
<p><?php echo __('Drop us a message using the form below:') ?></p>
<form action="<?php echo url_for('contact/index') ?>" method="post">
  <table>
    <?php echo $form ?>
    <tr>
      <td></td>
      <td><input type="submit" value="<?php echo __('Send your message') ?>" /></td>
    </tr>
  </table>
</form>

Maintenant, lançons la commande d'extraction des chaînes à traduire pour notre future version française, en lui demandant poliment de générer automatiquement le fichier de traduction et de supprimer automatiquement les entrées orphelines :

 $ ./symfony i18n:extract --auto-save --auto-delete main fr
>> i18n      extracting i18n strings for the "main" application
>> i18n      found "3" new i18n strings
>> i18n      found "0" old i18n strings
>> i18n      saving new i18n strings
>> i18n      deleting old i18n strings

Le fichier apps/main/i18n/fr/messages.xml a été généré, examinons son contenu :

<?xml version="1.0"?>
<xliff version="1.0">
  <file source-language="EN" target-language="fr" datatype="plaintext"
    original="messages" date="2008-03-13T11:13:45Z"
    product-name="messages">
    <body>
      <trans-unit id="1">
        <source>Contact us</source>
        <target></target>
      </trans-unit>
      <trans-unit id="2">
        <source>Drop us a message using the form below:</source>
        <target></target>
      </trans-unit>
      <trans-unit id="3">
        <source>Send your message</source>
        <target></target>
      </trans-unit>
    </body>
  </file>
</xliff>

Il ne nous reste plus qu'à traduire nos chaînes en remplissant les balises <target></target> en conséquence pour traduire notre application en français. Si l'on venait à modifier notre template en supprimant, modifiant ou ajoutant de nouvelles chaînes, la tâche d'extraction se chargerait de mettre à jour nos fichiers de traduction en conséquence, tout en préservant le travail déjà effectué :)

mercredi 12 mars 2008

Ma santé ne passera pas par Monsanto

[Via David]

À voir de toute urgence, si vous l'avez raté hier soir. Ça va rester 5 jours encore en ligne, après il faudra éventuellement commander le DVD.

mardi 11 mars 2008

Six choses, si j'ose...

Ouch, je viens de me faire Peper dans le dos à grand coup de YAC à l'insu de mon plein gré. Oui mais voilà, le boulot est déjà aux cinq sixièmes effectué, puisque j'avais déjà répondu à une sollicitation du même acabit il y a de cela quelques temps déjà.

Bon, ok, à l'époque j'avais mentionné cinq choses, il en manque donc une sixième. Allez et puisque c'est vous, vous en aurez trois, c'est jour de solde :)

  • Dans une vie antérieure, j'ai composé des musiques pour des dessins animés produits par La Cinquième. J'ai jamais déclaré les droits, et du coup si ça se trouve je suis passé à côté d'un gros paquet de blé. Ou pas.
  • La dernière fois que je suis monté sur un VTT j'ai fait un soleil et me suis retrouvé la tête dans une flaque de boue. Depuis, je suis jamais remonté dessus, et c'est même avec une certaine appréhension que j'enfourche occasionnellement un Vélib'.
  • Dans la même veine, j'ai eu un accident de moto spectaculaire fin 2004, avec glissade à plus de 60 km/h et moto fracassée contre un rebord de trottoir, Twingo orange qui me frôle le casque lancée pleine balle, cuir transpercé et j'ai pas eu une égratignure. Un miracle, un vrai. Ou un énorme coup de bol, aussi. Depuis, l'épave (la moto, pas moi !) dort toujours au fond du garage.

Voilà, ça, c'est fait. C'était pas forcément très gai mais c'est comme ça :p

Je vais passer le bébé (avec l'eau du bain) aux six compatriotes suivants :

  • NiCoS, pour l'embêter parce que sais qu'il aime pas les chaînes
  • kNo', pour l'embêter parce que sais qu'il aime pas les chaînes
  • mEga, pour l'embêter parce que sais qu'il aime pas les chaînes
  • Olivier, pour l'embêter parce que sais qu'il aime pas les chaînes
  • Nicolas Pestana, pour l'embêter parce que sais qu'il aime pas les chaînes
  • Pep, parce que j'ai vraiment envie de me venger mais je sais vraiment pas comment (et que lui imposer ça deux fois de suite ça s'approche doucement du pire des supplices) :p

mardi 11 mars 2008

Symfony 1.1 beta, tour du propriétaire - Les formulaires

Nous venons de voir la procédure d'installation de la beta1 de Symfony 1.1. Nous allons maintenant rentrer un peu plus dans les détails des nouvelles fonctionnalités en commençant par les formulaires.

La gestion des formulaires avec Symfony 1.1

La nouvelle gestion des formulaires est l'une des fonctionnalités majeures de cette nouvelle mouture du framework. Elle propose une séparation claire entre couche de contrôle, couche de définition et couche de présentation des données, soit un bon vieux pattern MVC des familles.

Pour illustrer ces fonctionnalités, nous allons retrousser nos manches et créer un formulaire de contact basique. On commence par initialiser un nouveau module contact dans l'application main de notre projet sf11test initié précédemment :

$ ./symfony generate:module main contact

Création d'une classe de formulaire

Nous allons créer une classe qui représentera notre formulaire de contact, que nous stockerons dans le fichier apps/main/lib/ContactForm.class.php. Cette classe étendra la classe de base sfForm et surchargera sa méthode de configuration afin de définir les champs de formulaire et les différents validateurs associés. Nous définirons quatre champs (appelés widgets en Symfony 1.1) :

  • Le nom de l'expéditeur, sous la forme d'un champs de saisie textuelle (<input type="text"/>)
  • Son adresse email, également sous la forme d'un champs de saisie textuelle
  • Le sujet de son message, sous la forme d'une boîte de sélection (<select/>)
  • Le texte de son message, sous la forme d'un champs texte multilignes (<textarea/>)
<?php
class ContactForm extends sfForm
{
  public function configure()
  {
    // Widgets
    $topics = sfConfig::get('app_contact_topics', array());
    $widgetSchema = new sfWidgetFormSchema(array(
      'topic'   => new sfWidgetFormSelect(array('choices' => $topics)),
      'name'    => new sfWidgetFormInput(),
      'email'   => new sfWidgetFormInput(),
      'message' => new sfWidgetFormTextarea()
    ));
    $widgetSchema->setNameFormat('contact[%s]'); // HTML field names format
    $this->setWidgetSchema($widgetSchema);
 
    // Validators
    $this->setValidators(array(
      'topic'   => new sfValidatorRegex(array('pattern' => '/[a-z_]/')),
      'name'    => new sfValidatorString(array('min_length' => 2,
                                               'max_length' => 45)),
      'email'   => new sfValidatorAnd(array(new sfValidatorEmail(),
                                            new sfValidatorString(array('max_length' => 100)))),
      'message' => new sfValidatorString(array('min_length' => 10)),
    ));
  }
}

Au passage, nous ajoutons les sujets possibles de message dans le fichier de configuration apps/main/config/app.yml :

all:
  contact:
    topics:
      carrots_request: Do you have carrots?
      eggs_request:    Do you have eggs?

Marquons un arrêt pour examiner de plus près ce que nous venons d'écrire :

  • Nous avons ajouté 4 widgets à notre formulaires,
  • Nous avons défini et paramétré leurs validateurs associés,
    • Au passage, vous noterez qu'il est possible de spécifier plusieurs validateurs pour un même champs, comme c'est ici le cas pour le champs email
  • Nous avons défini le format de nommage des champs de formulaire et choisi une syntaxe à base de tableau pour manipuler plus aisément les données dans notre action,
  • Nous avons déporté une partie de la configuration textuelle dans un fichier externe dédié, pour en faciliter la maintenance.

N'oublions pas de purger le cache de Symfony, car nous venons d'ajouter un nouvel objet php :

$ ./symfony cc

Interaction avec le formulaire depuis le contrôleur de l'application

Éditons maintenant le fichier apps/main/modules/contact/actions/actions.class.php pour y définir l'action par défaut du module[1] :

<?php
class contactActions extends sfActions
{
  public function executeIndex(sfWebRequest $request)
  {
    $form = new ContactForm();
    if ($request->isMethod('post')) // If HTTP method is POST
    {
      // Bind submitted values to the contact form instance
      $form->bind($request->getParameter('contact'));
      // Validate the form
      if ($form->isValid()) 
      {
        // Retrieve submitted values
        $values = $form->getValues(); 
        // ... Send your message here using submitted values
        // Then redirect user to the homepage with a one-shot message
        $this->getUser()->setFlash('notice', 'Message sent');
        $this->redirect('@homepage');
      }
    }
    // Publish form instance to the view
    $this->form = $form;
  }
}

Ici, dans l'ordre :

  • On instancie un objet de formulaire de contact
  • Si la méthode HTTP est POST :
    • On assigne les paramètres de la requête correspondant aux champs du formulaire de contact à ce dernier
    • On lance la validation, et si c'est valide :
      • On effectue les opérations nécessaires (traitement, redirection, etc.)

Vous noterez que tous les sinon sont gérés automatiquement par le framework de façon transparente (mais ces comportements par défaut sont toujours surchargeables) :

  • Par défaut le formulaire présenté sera vierge[2],
  • Les champs seront automatiquement préremplis en cas d'erreur de validation,
  • Les erreurs seront contextualisées par rapport aux champs.

Rendu du formulaire dans la vue

Enfin, il nous reste à créer un template pour présenter le formulaire et éventuellement afficher un message à l'utilisateur, dans notre vue gérée au travers du fichier apps/main/modules/contact/templates/indexSuccess.php :

<?php if ($sf_user->hasFlash('notice')): ?>
  <p class="notice"><?php echo $sf_user->getFlash('notice') ?></p>
<?php endif; ?>
 
<form action="<?php echo url_for('contact/index') ?>" method="post">
  <table>
    <?php echo $form ?>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

Si on charge la page /main_dev.php/contact, on a le résultat suivant :

Symfony 1.1 test form

Au passage si vous regardez la source, une protection anti CSRF est automatiquement gérée de façon transparente.

Bien entendu, le mode de rendu par défaut utilise un tableau pour la mise en forme, mais il existe un autre décorateur plus sémantique à base de liste. Pour l'utiliser, modifions notre classe ContactForm :

<?php
class ContactForm extends sfForm
{
  public function configure()
  {
   // ...
    $this->widgetSchema->setFormFormatterName('list');
  }
}

Il conviendra bien entendu d'adapter le template pour enlever les balises tables. On peut aussi imaginer de créer notre propre décorateur HTML. Par exemple, créeons la classe sfWidgetFormSchemaFormatterDiv comme suit :

<?php
class sfWidgetFormSchemaFormatterDiv extends sfWidgetFormSchemaFormatter
{
  protected
    $rowFormat       = "<div class=\"form-row\">\n  %error%%label%\n  %field%%help%\n%hidden_fields%</div>\n",
    $errorRowFormat  = "<div class=\"form-errors\">\n%errors%</div>\n",
    $helpFormat      = '<div class="form-help">%help%</div>',
    $decoratorFormat = "<div>\n  %content%</div>";
}

Encore une fois, modifions notre classe ContactForm pour l'utiliser (après avoir purgé le cache symfony, comme il se doit) :

<?php
class ContactForm extends sfForm
{
  public function configure()
  {
   // ...
    $this->widgetSchema->setFormFormatterName('div');
  }
}

Rendu des widgets

Vous me direz, un simple <?php echo $form ?> n'est pas très satisfaisant du point de vue de l'intégration HTML, qui nécessite bien souvent de prendre la main finement sur le code html généré. Le framework de formulaires de Symfony 1.1 apporte une solution en permettant de générer le rendu de chacun des widgets de façon indépendante

Imaginons par exemple que nous souhaitions gérer spécifiquement la présentation du champ name de notre formulaire ; notre template devient alors :

<?php if ($sf_user->hasFlash('notice')): ?>
  <p class="notice"><?php echo $sf_user->getFlash('notice') ?></p>
<?php endif; ?>
 
<form action="<?php echo url_for('contact/index') ?>" method="post">
  <table>
    <?php echo $form['topic']->renderRow() ?>
    <tr>
      <th><?php echo $form['name']->renderLabel() ?></th>
      <td>
        <?php echo $form['name']->renderError() ?>
        <?php echo $form['name']->render(array('class' => 'toto')) ?>
      </td>
    </tr>
    <?php echo $form['email']->renderRow() ?>
    <?php echo $form['message']->renderRow() ?>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

Vous noterez qu'on accède ici aux différents widgets du formulaire au moyen de clés de tableaux classiques ; c'est tout simplement car la classe sfForm implémente l'interface ArrayAccess de la SPL. C'est très pratique !

Le nerf de la guerre : la génération de formulaires à partir d'objets Propel

Ayant été à une lointaine époque un fervent adepte de PEAR::FormBuilder, brique permettant de générer des formulaires à partir d'instance d'objets de données ORM, j'étais curieux de voir comment cette fonctionnalité demandée par les développeurs depuis longtemps allait être implémentée dans Symfony 1.1 au travers de l'ORM Propel, bundlé par défaut[3].

Après avoir configuré un accès à notre SGBD préféré[4], nous allons définir une table contact_demand dans notre fichier config/schema.yml pour y stoker nos demandes de contacts :

propel:
  contact_demand:
    id:
    name:    { type: varchar, size: 45, required: true }
    email:   { type: varchar, size: 100, required: true }
    topic:   { type: varchar, size: 255, required: true }
    message: { type: longvarchar, required: true }
    created_at:

On lance rapidement la tâche de création de la table et des objets ORM associés :

$ ./symfony propel:build-all
$ ./symfony cc

Maintenant, allons faire un tour dans le répertoire lib/model pour voir ce qui a été généré. Surprise, des objets de formulaires ont été automatiquement créés pour nous !

Jetons un oeil plus particulièrement au fichier lib/form/base/BaseContactDemandForm.class.php :

<?php
class BaseContactDemandForm extends BaseFormPropel
{
  public function setup()
  {
    $this->setWidgets(array(
      'id'         => new sfWidgetFormInputHidden(),
      'name'       => new sfWidgetFormInput(),
      'email'      => new sfWidgetFormInput(),
      'topic'      => new sfWidgetFormInput(),
      'message'    => new sfWidgetFormTextarea(),
      'created_at' => new sfWidgetFormDateTime(),
    ));
 
    $this->setValidators(array(
      'id'         => new sfValidatorPropelChoice(array('model' => 'ContactDemand', 'column' => 'Id', 'required' => false)),
      'name'       => new sfValidatorString(),
      'email'      => new sfValidatorString(),
      'topic'      => new sfValidatorString(),
      'message'    => new sfValidatorString(),
      'created_at' => new sfValidatorDateTime(array('required' => false)),
    ));
 
    $this->widgetSchema->setNameFormat('contact_demand[%s]');
 
    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
 
    parent::setup();
 
  }
 
  public function getModelName()
  {
    return 'ContactDemand';
  }
}

Cela ne vous rappelle rien ? C'est presque quasiment ce que nous avions écrit manuellement précédemment dans notre classe ContactForm. On notera également la présence dans le fichier lib/form/ContactDemandForm.class.php de la classe ContactDemandForm, cette dernière héritant de BaseContactDemandForm.class.php, ce qui nous permettra de surcharger tout ou partie de ses méthodes pour adapter le formulaire généré à nos besoins.

En l'occurrence, il nous faut adapter un peu la méthode configure() pour retrouver notre sélecteur de sujets et réappliquer nos validateurs. Voici le code de la classe ContactDemandForm modifiée en conséquence :

<?php
class ContactDemandForm extends BaseContactDemandForm
{
  public function configure()
  {
    // Widgets
    $topics = sfConfig::get('app_contact_topics', array());
    $this->setWidgets(array(
      'id'      => new sfWidgetFormInputHidden(),
      'topic'   => new sfWidgetFormSelect(array('choices' => $topics)),
      'name'    => new sfWidgetFormInput(),
      'email'   => new sfWidgetFormInput(),
      'message' => new sfWidgetFormTextarea()
    ));
 
    // Validators
    $this->setValidators(array(
      'id'         => new sfValidatorPropelChoice(array('model'    => 'ContactDemand',
                                                        'column'   => 'Id',
                                                        'required' => false)),
      'topic'      => new sfValidatorRegex(array('pattern' => '/[a-z_]/')),
      'name'       => new sfValidatorString(array('min_length' => 2,
                                                  'max_length' => 45)),
      'email'      => new sfValidatorAnd(array(new sfValidatorEmail(),
                                               new sfValidatorString(array('max_length' => 100)))),
      'message'    => new sfValidatorString(array('min_length' => 10)),
      'created_at' => new sfValidatorDateTime(array('required' => false)),
    ));
 
    $this->widgetSchema->setNameFormat('contact_demand[%s]');
    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
  }
}

On va maintenant modifier notre action pour prendre en compte notre nouvelle classe de formulaire liée à notre objet Propel :

<?php
class contactActions extends sfActions
{
  public function executeIndex(sfWebRequest $request)
  {
    $form = new ContactDemandForm();
    if ($request->isMethod('post')) // If HTTP method is POST
    {
      // Bind submitted values to the contact form instance
      $form->bind($request->getParameter('contact_demand'));
      // Validate the form
      if ($form->isValid())
      {
        // Save submitted values in form's ContactDemand object
        $form->save();
        // Then redirect user to the homepage with a one-shot message
        $this->getUser()->setFlash('notice', 'Message sent');
        $this->redirect('@homepage');
      }
    }
    // Publish form instance to the view
    $this->form = $form;
  }
}

Ainsi, un simple $form->save() nous permet de persister en base les données soumises par l'utilisateur au travers du formulaire autogénéré. Un sacré gain de productivité en phase de prototypage, assurement !

En conclusion

Voilà, ce n'est bien évidemment là qu'une infime partie de ce que peut faire le nouveau système de gestion de formulaires de Symfony 1.1, mais c'est un peu à reculons que l'on retourne à l'ancien système ;-)

Notes

[1] Nous ne créons pas de route pour le moment, même si ce serait là une bonne pratique, afin de ne pas surcharger inutilement le contenu de ce tutorial, déjà bien assez dense comme ça :-)

[2] On aurait bien entendu pu proposer des valeurs par défaut.

[3] Le mécanisme de génération de code devrait permettre de proposer facilement la même fonctionnalité pour Doctrine prochainement.

[4] Je vous laisse le soin de vous référer au tutoriel existant sur ce même blog ;-)

lundi 10 mars 2008

Symfony 1.1 beta, tour du propriétaire - Installation

Il y a quelques jours, Fabien a annoncé la disponibilité de Symfony 1.1 beta 1 dans le dépôt du projet. Symfony 1.1 est un changement majeur au niveau architecture, et la compatibilité ascendante est rompue en de nombreux points. Pour un outil éminemment basé sur les conventions, cela implique une réappropriation de ces dernières quand elles ont changé - mais c'est là le prix à payer pour bénéficier des nouvelles fonctionnalités. Et elles valent le coup !

Ce billet sera donc le premier d'une série destinée à explorer les fonctionnalités phares de cette preversion. On commence par le commencement avec la procédure d'installation.

Remarques préliminaires

Nous ne verrons pas la procédure de mise à jour d'un projet en symfony 1.0 vers la version 1.1[1]. On verra ça plus en détail sur ce blog si les CNTP le permettent. Pour l'heure, on partira donc d'un projet vierge en 1.1.

Installation de Symfony 1.1

Il faut pour l'heure installer Symfony 1.1 à partir des sources subversion ; voici une démarche possible, en admettant que vous disposez d'un environnement Unix/Linux[2] :

$ mkdir vendor && cd vendor
$ svn co http://svn.symfony-project.com/branches/1.1/ symfony11
$ sudo ln -s `pwd`/symfony11/data/bin/symfony /usr/bin/symfony11

Je crée ici un lien symbolique symfony11 accessible depuis /usr/bin, ce qui permettra de gérer aussi bien des projets en 1.0 qu'en 1.1[3].

Pour vérifier que tout s'est bien déroulé, vous pouvez lancer cette commande :

$ symfony11 -V
symfony version 1.1.0-DEV (/Users/niko/www/vendor/symfony11/lib)

Création d'un nouveau projet

Grâce à notre nouvelle installation isolée de Symfony 1.1, on peut créer un projet et une nouvelle application main via cette série de commandes :

$ cd /path/to/workspace
$ mkdir sf11test && cd sf11test
$ symfony11 generate:project sf11test
$ ./symfony generate:app main

Vous noterez que toutes les commandes ont été renommées par rapport à la version 1.0 et qu'elles utilisent désormais des espaces de noms spécifiques à certains domaines : generate:, propel:, plugins:, log:, etc. Pour lister l'ensemble des tâches en lignes de commande disponibles, vous pouvez lancer la commande symfony11 telle quelle, ou utiliser l'executable symfony disponible à la racine de votre projet :

$ ./symfony

Notez que l'emploi de symfony11 ou ./symfony a la racine de votre projet ont ici strictement le même effet, puisque les deux exécutables référencent la même installation de Symfony.

Il nous reste à créer un VHost Apache[4] minimaliste pour accéder à notre projet au travers de notre navigateur :

<VirtualHost *>
  ServerName   local.sf11test.org
  DocumentRoot %PROJECT_ROOT%/web
  <Directory "%PROJECT_ROOT%/web">
    AllowOverride All 
    Allow from All 
  </Directory>
  Alias /sf    %VENDOR_ROOT%/symfony11/data/web/sf
  ErrorLog     %PROJECT_ROOT%/log/error.log
  CustomLog    %PROJECT_ROOT%/log/access.log common
</VirtualHost>

N'oubliez pas de remplacer les chaînes %PROJECT_ROOT% et %VENDOR_ROOT% par les chemins système correspondant (respectivement la racine du projet et la racine de votre répertoire vendor créé précédemment).

On ajoutera également une entrée dans le fichier /etc/hosts pour avoir la résolution du nom local.sf11test.org localement :

127.0.0.1       local.sf11test.org

Si toutes les étapes ont été correctement suivies et après avoir rechargé la configuration d'Apache, en lançant notre navigateur préféré sur l'adresse local.sf11test.org, nous obtenons :

Symfony 1.1 default homepage

Ça vous rappelle quelque chose ? ;-)

La suite au prochain épisode, avec les formulaires dont la gestion a été entièrement revue en Symfony 1.1.

Edit : J'ai modifié l'url du dépôt pour faire pointer vers la branche 1.1, qui évolue constamment, comme suggéré par Fabien en commentaire :)

Pour ceux qui veulent mettre à jour du tag vers la branche, il faut lancer cette commande à la racine de votre répertoire vendor :

$ svn switch http://svn.symfony-project.com/branches/1.1/ symfony11

Un petit ./symfony cc s'imposera dans vos projets utilisant le dépôt.

Notes

[1] La procédure est pour le moment documenté dans ce fichier sur le dépôt.

[2] Enfin je veux dire, je ne m'occuperai pas de Windows ;)

[3] En admettant bien sûr que vous disposiez déjà d'une installation fonctionnelle de la 1.0 ;)

[4] Comme toujours, mod_rewrite doit être activé.

mardi 4 mars 2008

Hihihi PC

L'EEE PC 700, avec son minuscule écran et ses capacités limitées ne m'a pas vraiment emballé, malgré un prix très agressif pour un ultra portable. Par contre, la prochaine mouture me fait de l'oeil comme c'est pas permis, surtout si le surcoût n'est que d'une centaine d'euros !

Donc si vous ne savez pas quoi m'offrir cet été, voila une piste.

Ben quoi, on peut toujours essayer, non ?

- page 6 de 70 -