<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://prendreuncafe.com/blog/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Prendre un Café - Tag - scaffolding</title>
  <link>http://prendreuncafe.com/blog/</link>
  <atom:link href="http://prendreuncafe.com/blog/feed/tag/scaffolding/rss2" rel="self" type="application/rss+xml"/>
  <description></description>
  <language>fr</language>
  <pubDate>Tue, 30 Dec 2008 16:33:00 +0100</pubDate>
  <copyright>Contenus sous licence Creative Commons BY-SA</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Gagnez du temps avec Symfony 1.0 et son générateur de back-office</title>
    <link>http://prendreuncafe.com/blog/post/2007/04/28/Gagnez-du-temps-avec-Symfony-et-son-generateur-de-back-office</link>
    <guid isPermaLink="false">urn:md5:976cd47651753a1d2e008e0e9e8380fa</guid>
    <pubDate>Sat, 28 Apr 2007 16:26:00 +0200</pubDate>
    <dc:creator>NiKo</dc:creator>
        <category>Dev</category>
        <category>bestpractices</category><category>framework</category><category>php</category><category>scaffolding</category><category>symfony</category><category>tutoriel</category>    
    <description>    &lt;p&gt;Lors du dernier &lt;a href=&quot;http://www.clever-age.com/actualites/petits-dejeuners/paris/&quot; hreflang=&quot;fr&quot;&gt;petit-déjeuner&lt;/a&gt; Clever Age que j'ai animé sur les frameworks PHP, j'ai effectué une démonstration des fonctionnalités de génération de back-office existantes dans &lt;a href=&quot;http://www.symfony-project.com&quot; hreflang=&quot;fr&quot;&gt;Symfony&lt;/a&gt; : la plupart des gens présents - pour la plupart découvrant la notion même de &lt;em&gt;framework&lt;/em&gt; - ont été très impressionnés par la facilité déconcertante avec laquelle il était possible de développer une application complète en très peu de temps et d'étapes techniques grâce au &lt;a href=&quot;http://www.symfony-project.com/book/trunk/14-Generators#Administration&quot; hreflang=&quot;en&quot;&gt;générateur d'admin&lt;/a&gt;...&lt;/p&gt;


&lt;p&gt;Personnellement, je suis tellement habitué à travailler avec de tels outils désormais que j'oublie parfois comme la vie est plus difficile sans eux... Je vais donc faire une démonstration afin que chacun puisse se faire son idée, sur sa propre machine &lt;img src=&quot;/blog/themes/battlestar/smilies/smile.gif&quot; alt=&quot;:)&quot; class=&quot;smiley&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Pour faire très original, on va créer une petite application sommaire de gestion de weblog, doté des fonctionnalités suivantes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un auteur par billet&lt;/li&gt;
&lt;li&gt;Billets multi-catégoriques (on pourrait aussi parler de tags)&lt;/li&gt;
&lt;li&gt;Commentaires pour chaque billet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L'avantage est que la plupart des frameworks web proposent ce type de tutoriaux, donc ainsi vous pourrez plus aisément comparer &lt;img src=&quot;/blog/themes/battlestar/smilies/smile.gif&quot; alt=&quot;:)&quot; class=&quot;smiley&quot; /&gt;&lt;/p&gt;


&lt;h3&gt;Installation de Symfony&lt;/h3&gt;


&lt;p&gt;Je vous renvoie à la &lt;a href=&quot;http://www.symfony-project.com/book/trunk/03-Running-Symfony&quot; hreflang=&quot;fr&quot;&gt;documentation officielle&lt;/a&gt; ou à &lt;a href=&quot;http://prendreuncafe.com/blog/post/2006/06/20/473-installer-le-framework-php-symfony-sur-ubuntu-dapper-drake&quot; hreflang=&quot;fr&quot;&gt;ce tutoriel&lt;/a&gt; pour installer Symfony sur votre machine et configurer un &lt;a href=&quot;http://httpd.apache.org/docs/2.2/fr/vhosts/examples.html&quot; hreflang=&quot;fr&quot;&gt;vhost apache&lt;/a&gt; pour votre nouveau projet. On partira sur la &lt;strong&gt;version 1.0.2&lt;/strong&gt;, soit la dernière version stable disponible à l'heure où sont écrites ces quelques lignes.&lt;/p&gt;


&lt;h3&gt;Création d'un nouveau projet&lt;/h3&gt;


&lt;p&gt;Imaginons que votre projet soit créé dans /var/www :&lt;/p&gt;


&lt;pre&gt;$ sudo -s
# cd /var/www
# mkdir sftest &amp;amp;&amp;amp; cd sftest
# symfony init-project sftest&lt;/pre&gt;


&lt;p&gt;Note: Si la page web par défaut du projet n'affiche pas d'images, il se peut que votre vhost ne trouve pas les éléments médias génériques de Symfony ; dans ce cas, un lien symbolique comme ci-dessous devrait régler le problème :&lt;/p&gt;


&lt;pre&gt;# ln -s /usr/share/php/data/symfony/web/sf web/sf&lt;/pre&gt;


&lt;p&gt;Note : Vous pourriez tout autant utiliser un alias apache dans votre vhost.&lt;/p&gt;


&lt;p&gt;Créons maintenant nos deux applications &lt;code&gt;front&lt;/code&gt; et &lt;code&gt;back&lt;/code&gt; qui recevront le front-office et la console d'administration de notre projet :&lt;/p&gt;


&lt;pre&gt;# symfony init-app front 
# symfony init-app back&lt;/pre&gt;


&lt;p&gt;On crée une base de données dédiée au projet :&lt;/p&gt;


&lt;pre&gt;# mysql -uroot -p
&amp;gt; CREATE DATABASE sftest CHARACTER SET utf8 COLLATE utf8_general_ci;
&amp;gt; GRANT ALL ON sftest.* TO sftest@localhost IDENTIFIED BY '1234567'
&amp;gt; FLUSH PRIVILEGES;
&amp;gt; \q&lt;/pre&gt;


&lt;h3&gt;Configuration de l'accès à la base de données&lt;/h3&gt;


&lt;p&gt;D'abord, on renseigne notre &lt;acronym title=&quot;Data Source Name&quot;&gt;DSN&lt;/acronym&gt; MySQL dans le fichier &lt;code&gt;config/databases.yml&lt;/code&gt; :&lt;/p&gt;


&lt;pre&gt;all:
  propel:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://sftest:1234567@localhost/sftest&lt;/pre&gt;


&lt;p&gt;On fait la même chose pour Propel, dans le fichier &lt;code&gt;config/propel.ini&lt;/code&gt; :&lt;/p&gt;


&lt;pre&gt;propel.database.url = mysql://sftest:1234567@localhost/sftest&lt;/pre&gt;


&lt;h3&gt;Configuration du modèle de données&lt;/h3&gt;


&lt;p&gt;On crée le schéma de base notre de données, dans le fichier &lt;code&gt;config/schema.yml&lt;/code&gt; :&lt;/p&gt;

&lt;pre&gt;
propel:

  blog_authors:
    _attributes:    { phpName: Author }
    id: 
    name:           varchar(255)
    email:          varchar(255)

  blog_posts:
    _attributes:    { phpName: Post }
    id: 
    title:          varchar(255)
    excerpt:        longvarchar
    body:           longvarchar
    author_id:
    created_at:
    updated_at:
  
  blog_comments:
    _attributes:    { phpName: Comment }
    id: 
    post_id:
    author:         varchar(255)
    email:          varchar(255)
    site:           varchar(255)
    content:        longvarchar
    created_at:

  blog_sections:
    _attributes:    { phpName: Section }
    id: 
    name:           varchar(255)

  blog_posts_sections:
    _attributes:    { phpName: PostSection }
    id: 
    post_id:
    section_id:
&lt;/pre&gt;


&lt;p&gt;Il y a beaucoup de magie dans la syntaxe de ce fichier. Retenez juste que les champs &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;*_id&lt;/code&gt; et &lt;code&gt;*_at&lt;/code&gt; sont nommés en vertus de conventions Symfony pour gérer automatiquement clés primaires, clés étrangères et les champs de type DATETIME.&lt;/p&gt;


&lt;h3&gt;Création d'un jeu de données de test&lt;/h3&gt;


&lt;p&gt;De même et parce qu'on est des gens sérieux (mais surtout parceque c'est pratique), on crée d'emblée un jeu de données de test (ou &lt;em&gt;fixtures&lt;/em&gt;), dans un nouveau fichier &lt;code&gt;data/fixtures/data.yml&lt;/code&gt; :&lt;/p&gt;

&lt;pre&gt;
Author:
  NiKo:
    name:    NiKo
    email:   tepafou@fai.com

Post:
  FirstPost:
    title:   Mon premier post !
    excerpt: Un premier billet prometteur...
    body: &amp;gt;
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer 
      consectetuer congue diam. Sed eu enim. Cras fringilla, erat et pretium 
      tincidunt, elit nibh imperdiet lectus, vel viverra erat velit in  
      metus. Ut ipsum ante, ornare luctus, hendrerit in, ultricies id, est.
    author_id: NiKo
  
  SecondPost:
    title:   Mon deuxième billet
    excerpt: Un deuxième billet tout aussi savoureux.
    body: &amp;gt;
      Suspendisse potenti. Mauris id risus. Cras urna. Etiam vel enim nec 
      dui ultrices condimentum. Curabitur bibendum ultrices quam. Nulla 
      sodales risus eget nunc.
    author_id: NiKo

Section:
  Humeurs:
    name:    Humeurs
  Geek: 
    name:    Geek
  Ubuntu:
    name:    Ubuntu

PostSection:
  # First post categories
  FirstPost_Humeurs:
    post_id: FirstPost
    section_id: Humeurs
  FirstPost_Geek: 
    post_id: FirstPost
    section_id: Geek

  # Second post categories
  SecondPost_Geek:
    post_id: SecondPost
    section_id: Geek
  SecondPost_Geek: 
    post_id: SecondPost
    section_id: Ubuntu

Comment:
  Comment1:
    post_id: FirstPost
    author:  Jean-Paul
    email:   &amp;quot;jp@fai.com&amp;quot;
    site:    &amp;quot;http://blog.jeanpaul.com&amp;quot;
    content: Bravo, belle intervention.

  Comment2:
    post_id: SecondPost
    author:  Jean-Luc
    email:   &amp;quot;jl@fai.com&amp;quot;
    site:    &amp;quot;http://blog.jeanluc.org&amp;quot;
    content: Exactement, vous avez raison.
&lt;/pre&gt;


&lt;p&gt;Ceci fait, on va lancer la génération du fichier SQL et des classes représentant notre modèle, créer les tables physiquement dans notre base et insérer notre jeu de données de test :&lt;/p&gt;


&lt;pre&gt;# symfony propel-build-all-load back&lt;/pre&gt;


&lt;p&gt;Vous noterez qu'un seule ligne de commande est à appeller, ce qui simplifie grandement les phases de prototypage.&lt;/p&gt;


&lt;p&gt;Note : En cas de modification profonde du modèle de données, il est vivement conseillé de vider le cache symfony :&lt;/p&gt;


&lt;pre&gt;# symfony cc&lt;/pre&gt;


&lt;h3&gt;Ajout des méthodes &lt;code&gt;__toString()&lt;/code&gt; aux objets de données&lt;/h3&gt;


&lt;p&gt;Afin d'avoir facilement un descripteur texte pour notre objet &lt;code&gt;Author&lt;/code&gt;, nous allons implémenter une méthode &lt;code&gt;__toString()&lt;/code&gt; dans sa classe associée située dans le fichier &lt;code&gt;lib/model/Author.php&lt;/code&gt; :&lt;/p&gt;

&lt;pre class=&quot;php&quot;&gt;&lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;class&lt;/span&gt; Author extends BaseAuthor
&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;
  public &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;function&lt;/span&gt; __toString&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;
  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&quot;color: #006600;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;
  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Cette méthode retournera le contenu du champs &lt;code&gt;name&lt;/code&gt; de l'enregistrement de la table &lt;code&gt;blog_authors&lt;/code&gt; correspondant pour identifier l'objet PHP sous la forme d'une chaîne de caractère descriptive. Vous pouvez aussi adapter ce principe pour les objets &lt;code&gt;Post&lt;/code&gt; et &lt;code&gt;Section&lt;/code&gt;, par exemple.&lt;/p&gt;


&lt;h3&gt;Génération d'un back-office d'administration des billets&lt;/h3&gt;


&lt;p&gt;Maintenant, on va générer une interface d'administration de nos objets &lt;code&gt;Post&lt;/code&gt;, accessible par un contrôleur &lt;code&gt;/posts&lt;/code&gt; depuis notre application &lt;code&gt;back&lt;/code&gt; :&lt;/p&gt;


&lt;pre&gt;# symfony propel-init-admin back posts Post&lt;/pre&gt;


&lt;p&gt;L'interface d'administration est maintenant accessible via &lt;code&gt;/back_dev.php/posts&lt;/code&gt; derrière la racine de l'url de votre instance projet Symfony &lt;img src=&quot;/blog/themes/battlestar/smilies/smile.gif&quot; alt=&quot;:-)&quot; class=&quot;smiley&quot; /&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://prendreuncafe.com/blog/public/images/Geekeries/Symfony/sf_admin_posts1.png&quot;&gt;&lt;img src=&quot;http://prendreuncafe.com/blog/public/images/Geekeries/Symfony/.sf_admin_posts1_s.jpg&quot; alt=&quot;Administration des billets&quot; style=&quot;display:block; margin:0 auto;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;C'est un peu sec par défaut et les sections associées aux billets du blog ne sont pas gérées, il nous faut donc adapter le fichier de configuration du générateur d'admin de Symfony pour ce module, situé dans le fichier &lt;code&gt;apps/back/modules/posts/config/generator.yml&lt;/code&gt; :&lt;/p&gt;

&lt;pre&gt;
generator:
  class:               sfPropelAdminGenerator
  param:
    model_class:       Post
    theme:             default

    # Customisation des colones de la vue en liste, lien d'édition sur le titre
    list:
      display:         [=title, excerpt, Author, created_at, updated_at]

    # Customisation du formulaire d'ajout/édition
    edit:
    
      # Champs personnalisés
      fields:
        # Création d'un champs d'administration des sections associées
        post_sections: { type: admin_check_list, params: through_class=PostSection }
    
      # Spécification des champs de formulaire à afficher
      display:         [author_id, title, excerpt, body, post_sections]
&lt;/pre&gt;


&lt;p&gt;Un raffraîchissement des interfaces en mode développement (en appellant le contrôleur &lt;code&gt;back_dev.php&lt;/code&gt; dans l'url) affichera nos interfaces modifiées en conséquences. Si vous utilisez le contrôleur de production (&lt;code&gt;/back.php&lt;/code&gt;), n'oubliez pas de vider le cache symfony pour visualiser vos modifications :&lt;/p&gt;


&lt;pre&gt;# symfony cc&lt;/pre&gt;


&lt;p&gt;On reproduira exactement la même opération pour nos autres objets à administrer (&lt;code&gt;Author&lt;/code&gt;, &lt;code&gt;Comment&lt;/code&gt; et &lt;code&gt;Section&lt;/code&gt;):&lt;/p&gt;


&lt;pre&gt;# symfony propel-init-admin back authors Author
# symfony propel-init-admin back sections Section
# symfony propel-init-admin back comments Comment&lt;/pre&gt;


&lt;p&gt;Voila, une vingtaine de minutes nous auront suffit pour générer une application en ligne relativement complète. Il restera à gérer notamment :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;la &lt;a href=&quot;http://www.symfony-project.com/book/trunk/06-Inside-the-Controller-Layer#Action%20Security&quot; hreflang=&quot;en&quot;&gt;sécurité d'accès&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;l'affichage des commentaires pour chaque billet&lt;/li&gt;
&lt;li&gt;l'&lt;a href=&quot;http://www.symfony-project.com/book/trunk/07-Inside-the-View-Layer#Templating&quot; hreflang=&quot;en&quot;&gt;affichage en front office&lt;/a&gt; des billets&lt;/li&gt;
&lt;li&gt;améliorer l'ergonomie et la présentation de ce back-office, par exemple en surchargeant ses éléments générés (&lt;a href=&quot;http://www.symfony-project.com/book/trunk/14-Generators#Administration&quot; hreflang=&quot;fr&quot;&gt;documentation complète&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amusez-vous bien &lt;img src=&quot;/blog/themes/battlestar/smilies/smile.gif&quot; alt=&quot;:-)&quot; class=&quot;smiley&quot; /&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p style='margin:.5em 0;padding:.5em;border:1px solid #333;background:#eee;color:#222'&gt;&lt;small&gt;Ce billet intitulé &lt;a href='http://prendreuncafe.com/blog/post/2007/04/28/Gagnez-du-temps-avec-Symfony-et-son-generateur-de-back-office'&gt;Gagnez du temps avec Symfony 1.0 et son générateur de back-office&lt;/a&gt; a été rédigé par &lt;a href='http://prendreuncafe.com/cv'&gt;Nicolas Perriault&lt;/a&gt; et publié sur le blog &lt;a href='http://prendreuncafe.com/blog/'&gt;Prendre un Café&lt;/a&gt; sous licence &lt;a href='http://creativecommons.org/licenses/by-nc-sa/2.5/'&gt;Creative Commons BY-NC-SA&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;</description>
    
    
    
      </item>
    
</channel>
</rss>
