Internationalisation et formulaire avec Symfony

Aujourd’hui on va traiter des formulaires et de l’internationalisation. Une des grandes fierté de Symfony 1.2 est l’internationalisation et les formulaires.  Vous avez  eu droit à leur chapitre dans les jobeet. En revanche lorsque l’on veut  coupler les deux, les choses se compliquent un peu et c’est bien là l’intérêt de notre métier. Le but de cet article n’étant pas d’expliquer une nouvelle fois le fonctionnement des formulaires ou de l’I18N, vous comprendrez que je survole certains points. Je vous renverrez simplement ici pour les formulaires et ici pour l’I18N .

Le but est d’obtenir un site (un bout de site) qui nous permette de faire un listing de recettes et cela dans différentes langues, on va se contenter du français et de l’anglais. Il faut d’abord commencer par le schéma :

 Recipe:
  actAs:
    I18n:
      fields: [name, body, is_activated]
    actAs:
      Sluggable: { fields: [name], uniqueBy: [lang, name] }
  columns:
    name: { type: string(255)}
    body: { type: clob}
    is_activated: { type:boolean, notnull: true, default: 0}

Le schema est très simple il n’y aucune relation avec d’autres tables, ce qui nous intéressent ici c’est le traitement I18N et les formulaires. Petite remarque : – Je passe le is_activated, qui indique si la recette est active ou non, dans le actAs I18N ainsi les recettes par langue seront totalement indépendantes. – Le sluggable est passé également en deuxième niveau d’actAs pour permettre à chaque langue d’avoir son propre slug. – Dernier point, il ne faut surtout pas mettre de unique : true dans la partie columns de notre schema, sinon on va se retrouver à ne pas pouvoir mettre à jour une langue indépendament de l’autre. Maintenant que l’on visualise le schéma et donc les classes qui en découlent on va parler code. Comme on en a l’habitude on va générer nos modèles, notre CRUD de recettes. On va maintenant s’attaquer à notre classe RecipeForm.class.php, on veut que l’utilisateur n’ai pas à rentrer les recettes dans les deux langues mais uniquement dans la sienne. Pour cela il faut lui afficher uniquement le formulaire rattaché à sa culture. Modifions notre classe:

 class RecipeForm extends BaseRecipeForm
 {
   private $lang; 

   public function __construct($lang = 'fr')
   {
      $this->lang = $lang; 

      parent::__construct();
   }
 }

La première étape est donc de redéfinir le constructeur de notre classe auquel on va soumettre une langue par défaut et de créer un attribut privé pour définir la langue ($lang). On va maintenant définir l’affichage de notre formulaire en modifiant la fonction configure()

public function configure()
{
  if (!is_array($this->lang))
  {
    $cultures = array($this->lang);
  }
  else
  {
    $cultures = $this->lang;
  } 

  foreach ($cultures as $culture)
  {
    $i18nObject = $this->object->Translation[$culture];
    $i18n = new RecipeTranslationForm($i18nObject);
    unset($i18n['id'], $i18n['lang'], $i18n['is_activated']);
    $i18n->widgetSchema['name'] = new sfWidgetFormInput(array(), array('size'=> 60));
    $i18n->widgetSchema['body'] = new sfWidgetFormTextarea(array(), array('cols'=> 58,'rows'=> 12));
    $this->embedForm($culture, $i18n);
  }
}

Dans notre action on va appeler ce formulaire comme suit :

public function executeNew(sfWebRequest $request)
{
  $this->culture = $this->getUser()->getCulture();
  $this->form = new RecipeForm($this->culture);
}

Vous noterez que l’on passe la culture en attribut ainsi on peut le récupérer dans le template :

render()

Il vous suffit de mettre désormais tout les champs et les label à afficher et le tour est joué.

Voir l’étude de cas
Lire l’article
Voir le témoignage
Fermer