Symfony pour un développement rapide

Mai 26, 07 Symfony pour un développement rapide

Enfin, j’émerge, après une semaine de développement où j’ai pu apprécier la puissance du Framework Français (mais totalement anglophone) Symfony (en PHP5), l’un des plus solide et performant, utilisé par 20 millions d’utilisateurs de Yahoo Bookmark’s

Quand on utilise la puissance de ce type d’outil et quand on pense que Ruby on Rail en ai une figure de proue avec une version stable depuis 2005 on se demande ce que Zend était en train de faire pendant ce temps là, en nous proposant encore aujourd’hui une version Beta

Principe de MVC (Model View Controller)

Ce principe permet une séparation entre le Modèle qui permet la manipulation de données, la Vue qui affiche ces données (templates) et le Contrôleur qui indique quoi faire pour une action donnée.

Ruby MVC Model View Controller Symfony MVC Model View Controller

Revenons sur les étapes de création d’un projet sous un framework tel Symfony, je passe volontairement l’aspect installation qui n’est pas évidente et qui peut être longue, mais qui n’a lieu qu’une fois, imaginons alors que nous sommes sur notre deuxième projet, et découvrons les 10 grandes étapes du développement d’un projet jusqu’à sa mise en ligne.

1- Définition de la base de donnée

Le fichier schema.yml peut être très simple et le moteur Propel reconnaît automatiquement :
– les clés primaires id et les clés étrangères nomtable_id,
– les champs created_at et updated_at, qui sont mise à jour automatiquement

propel:

 rubrique:
   _attributes:          { phpName: Rubrique }
   id:                   
   titre:                varchar(255)
   titre_menu:           varchar(50)    
   meta_description:     varchar(255)
   meta_title:           varchar(50)
   url:                  varchar(255)         
   en_ligne:             tinyint
   classement:           tinyint                  
   created_at:
   updated_at:    

 article:
   _attributes:          { phpName: Article }
   id:                   
   rubrique_id:
   titre:                varchar(255)
   sous_titre:           varchar(255)    
   chapo:                longvarchar
   article:              longvarchar
   url:                  varchar(255)         
   en_ligne:             tinyint  
   classement:           tinyint                  
   created_at:
   updated_at:

La commande symfony « symfony propel-build-sql » permet ensuite de générer automatiquement le fichier SQL (data/sql/lib.model.schema.sql), qu’on peut lancer en cli avec une commande Mysql ou sous PhpMyAdmin.

2- Préparation de l’insertion de données test

La destruction et la reconstruction (parfois fréquente) des tables rendent l’insertion d’information fastidieuse, c’est pourquoi il est prévu un fichier /data/fixtures/data.yml, qui permet d’insérer automatiquement les informations dans la base.

 Rubrique:

 Rubrique1:
   titre:                Ma Rubrique1 la plus cool
   titre_menu:           Rubrique1
   meta_description:     Description Ma Rubrique1 la plus cool
   meta_title:           Title Ma Rubrique1 la plus cool 
   url:                  rubrique1-la-plus-cool 
   en_ligne:             1

Article:

 Article1:
   rubrique_id:          Rubrique1
   titre:                    Article1 
   sous_titre:           Sous-titre Article1 
   chapo:                Chapo Article1 
   article:              <p>Article1</p>
   url:                      article1        
   en_ligne:             1

Le fichier propel.ini permet de configurer par exemple le type de Base propel.mysql.tableType = InnoDB

ou encore d’émuler les Ondelete Cascade si la base ne les gèrent pas propel.emulateForeignKeyConstraints = true

Dans databases.yml, on configure les accès SQL et l’encodage par défaut :

 all:
  propel:
   class:          sfPropelDatabase
   param:
     dsn:          mysql://root:@localhost/mabase
     encoding:     utf8      # Default charset for table creation

3- Création d’un projet et d’une application

Symfony considère qu’un projet est composé d’une base, mais qu’il peut y avoir plusieurs applications y travaillant avec une interface différente, ce qui en général le cas avec un /apps/fo/ (front office) et un bo (back office).

Créons alors le projet, qui générera la structure globale (à noter que c’est préalable à l’étape 1) : symfony init-project monprojet

Et l’application, qui générera les fichiers de structure de l’application (fo/templates/layout.php et fichiers de config de l’appli dans fo/config/) symfony init-app fo

4- Création des Classes de manipulation des tables

Pour chacune des tables sont générées des classes de « Base » (/lib/model/om/BaseArticle.php et BaseArticlePeer.php), auquel il ne faudra évidemment pas toucher, et des classes filles vides (/lib/model/Article.php et ArticlePeer.php), qui permettront d’ajouter des fonctions utilisateurs.

Ce qui est très intéressant, c’est que si l’on n’a pas de besoin d’accès direct à la Base et que l’on conserve donc le driver Créole, il n’y a pas de code SQL à réaliser et qu’ainsi il est possible de changer de type de base très facilement en changeant seulement les configurations.

La commande suivante en plus de générer les classes pemets d’ajouter les informations date.yml dans la base : symfony propel-build-all-load fo

5- Création des modules d’affichages

Pour chacune des tables il est possible de créer un module en scaffolding, avec par défaut la possibilité de lister (list), de voir (show), de créer (create->update), d’éditer (edit->update), et de supprimer (delete), soit le traditionnel CRUD (Create, Read, Update, Delete)

Symfony créait pour cela une classe de type action (fo/module/article/template/actions/actions.class.php) avec les fonctions listés précédemment et trois templates correspondants :
– fo/module/article/templates/listSuccess.php
– editSuccess.php (create/edit)
– showSuccess.php.

Dans notre exemple il est intéressant d’avoir la liste des articles en fo : symfony propel-generate-crud fo article Article

6- Modification des actions d’un module

Par défaut la fonction de listing est sans critères :

 public function executeList()
 {
   $this->articles = ArticlePeer::doSelect(new Criteria());
 }

Dans notre cas on peut souhaiter afficher la liste des articles liées à la rubrique courante, en ligne et classé par ordre.

$rubriqueId = $this->getRequestParameter('rubriqueid')

$c = new Criteria();
$c->add(ArticlePeer::RUBRIQUE_ID, $rubriqueId);
$c->add(ArticlePeer::EN_LIGNE, 1 );
$c->addAscendingOrderByColumn(ArticlePeer::CLASSEMENT);

$this->articles = ArticlePeer::doSelect($c);

Joli non ?

7- Modification d’un template d’un module

Par défaut le template est assez simple $this->variable dans une fonction de la classe actions, permet de récupérer directement une variable $variable dans le template lié.

Vous remarquerez aussi la fonction link_to (‘Anchor Text’, ‘monmodule/monaction’), qui permet de créer un lien assez facilement vers les modules et actions, je développerai ce point dans un futur billet spécial sur l’ urlrewriting de Symfony.

List

<?php
// auto-generated by sfPropelCrud
// date: 2007/05/03 12:20:41
?>
<h1>article</h1>
<table>
<thead>
<tr>
 <th>Id</th>
 <th>Rubrique</th>
 <th>Titre</th>
 <th>Sous titre</th>
 <th>Chapo</th>
 <th>Article</th>
 <th>Url</th>
 <th>En ligne</th>
</tr>
</thead>
<tbody>
<?php foreach ($articles as $article): ?>
<tr>
   <td><?php echo link_to($article->getId(), 'article/show?id='.$article->getId()) ?></td>
     <td><?php echo $article->getRubriqueId() ?></td>
     <td><?php echo $article->getTitre() ?></td>
     <td><?php echo $article->getSousTitre() ?></td>
     <td><?php echo $article->getChapo() ?></td>
     <td><?php echo $article->getArticle() ?></td>
     <td><?php echo $article->getUrl() ?></td>
     <td><?php echo $article->getEnLigne() ?></td>
 </tr>
<?php endforeach; ?>
</tbody>
</table>
<?php echo link_to ('create', 'article/create') ?>

Edit

<<?php
// auto-generated by sfPropelCrud
// date: 2007/05/03 12:20:41
?>
<?php use_helper('Object') ?>

<?php echo form_tag('article/update') ?>

<?php echo object_input_hidden_tag($article, 'getId') ?>

<table>
<tbody>
<tr>

 <th>Titre:</th>
 <td><?php echo object_input_tag($article, 'getTitre', array (
 'size' => 80,

)) ?></td>
</tr>
<tr>

 <th>Article:</th>
 <td><?php echo object_textarea_tag($article, 'getArticle', array (
 'size' => '30x3', ‘rich’=>true

)) ?></td>

NB : L’intégration de TinyMCE dans un textarea est très simple puisqu’il suffit d’ajouter une option ‘rich’=>true à la fonction textarea_tag().

8- Vérification de formulaire

Imaginons que les internautes peuvent ajouter des articles, les vérifications de formulaires sont très simplifiées, puisqu’il suffit d’ajouter un fichier fo/module/article/validate/update.yml (nom de fichier correspondant au nom de l’action de mise à jour).

fillin:

 enabled:       true # Lors d’erreurs permet la réinsertion des informations
fields:

 titre:      

   required:         true 
     msg:            Champ requis  

   sfStringValidator:
     min:            3
     min_error:      Doit être &gt;= à 3 caractères
     max:            50                                      
     max_error:      Doit être &lt;= à 50 caractères
 url:         

   required:         true 
     msg:            Champ requis  

   sfStringValidator:
     min:            3
     min_error:      Doit être &gt;= à 3 caractères
     max:            50                                      
     max_error:      Doit être &lt;= à 50 caractères 

   sfRegexValidator:
     match:          Yes
     match_error:    Ne doit pas comporter de majuscule ni de caractères spéciaux sauf "-"
     pattern:        /^[a-z0-9-]*$/

A cela doit s’ajoute une fonction indiquant quelles actions à mener en cas d’erreur, qui peut être de cette forme si l’on considère que la modification d’un article est possible.

 public function handleErrorUpdate() {
  if ($this->getRequestParameter('id')) $this->forward('categorie', 'edit');
  else $this->forward('categorie', 'create');
 }

Et l’affichage des erreurs dans le Template Edit avec l’appel aux fonctions d’aides de validation:

Validatiob Symfony

<?php use_helper('Object', 'Validation') ?>
...

 <th>Url:</th>
 <td>
 <?php  echo form_error('url') ?>
 <?php echo object_input_tag($article, 'getUrl, array (
 'size' => 80)

9- Un scaffolding spécial Back-Office

Symfony Admin CRUD

Symfony prévoit par ailleurs la génération d’un CRUD spécial Back-Office, où les templates, les fonctions de recherche et de validations sont déjà générées dans un même fichier generator.yml

Puissant, mais avec évidemment un manque de souplesse certain.

symfony propel-init-admin bo post Post

generator:

class:              sfPropelAdminGenerator
 param:
   model_class:      Post
   theme:            default
   fields:
     title:          { name: Titre }
     excerpt:        { name: Chapô }
     body:           { name: Body }
     nb_comments:    { name: Commentaire }
     created_at:     { name: Creation date }
   list:
     title:          Liste de Post
     layout:         tabular
     display:        [=title, excerpt, nb_comments, created_at]
     object_actions:
       _edit:        ~
       _delete:      ~
     max_per_page:   2
     filters:        [title, body, created_at]
   edit:
     title:          Détail du Post
     fields:
       title:           { type: input_tag, params: size=53 }
       excerpt:      { type: textarea_tag, params: size=50x2 }
       body:         { type: textarea_tag, params: size=50x10 }
       created_at:   { type: input_date_tag, params: rich=on }

10- Mise en ligne

Symfony tourne sur tout type d’hébergement PHP5, pour la mise en ligne il faut désolidariser le projet de l’environnement ce qu’on fait le plus simplement du monde avec la commande : symfony freeze

Une fois l’upload effectué la commande inverse unfreeze permet de revenir en environnement de développement.

A noter tout de même qu’il peut y avoir des particularités selon les hébergeurs, il faut par exemple réalisé un hack pour OVH, qui n’autorise au web que le dossier ‘www’, je ferais un billet spécial à ce sujet, car les nombreuses solutions trouvés n’ont pas été suffisante dans mon cas.

10bis- Des plugins pour un gain de temps encore plus important

En plus de l’intégration (qui consiste en un simple copier-coller) de TinyMCE et de la librairie Javascript Prototype (en attendant la version stable de la librairie Jquery), deux plugins semble souvent indispensable : La bibliothèque

La gestion des utilisateurs et des différents niveaux de permissions

Voir aussi

Le traditionnel bac à sable Symfony avec la création d’un blog en 1h

4 Comments

  1. Bonjour à tous,
    Dans databases.yml, cette ligne est effectivement utile:
    encoding: utf8

    Par contre le commentaire est inapproprié:
    # Default charset for table creation
    Il s'agit bien du charset pour accès à la base de données.

    Les créations de tables utilisent plutôt le fichier propel.ini

  2. Bonjour Heidy,

    Je ne serai pas aussi catégorique, dans tous les cas faut voir ca avec les auteurs du livre Symfony 😀
    <a href="http://www.symfony-project.com/b… » target= »_blank »>www.symfony-project.com/b…

  3. ROR est d'un simplicité deconcertante, suite à une contrainte d'hébergement, je m'attaque au framework symfony… et je dois bien avouer que je trouve le ruby 100x plus confortable, et que le framework en lui même est plus simple à appréhender.

  4. merci pour cet article.
    Une fois qu’on a pris l’habitude de symfony on ne peut plus s’en passer !

Leave a Comment

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *