<?xml version="1.0" encoding="ISO-8859-1"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">

<channel>
    <title>Novius Labs - Catégorie : Le Cervo : blog, tutoriaux, recherches</title>
    <link>http://www.novius-labs.com/cervo-blog-tutoriaux-recherches,c,4.html</link>
    <description>Flux RSS de la catégorie Le Cervo : blog, tutoriaux, recherches de Novius Labs</description>
    <atom:link href="http://www.novius-labs.com/cervo-blog-tutoriaux-recherches,c,4.html?feed=billets" rel="self" type="application/rss+xml" />

   <item>
       <title>Deux occasions de vous former à l'expérience utilisateur avant l'été</title>
       <link>http://www.novius-labs.com/deux-occasions-vous-former-experience-utilisateur-avant-ete,47.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_47_vignette.jpg</img>
       <guid>http://www.novius-labs.com/deux-occasions-vous-former-experience-utilisateur-avant-ete,47.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_47_vignette.jpg&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Nous sommes entrés dans l'ère post-PC : Internet est aujourd'hui multi-devices et multicanal. L'expérience des internautes est loin de se limiter aux seuls sites web. Comment optimiser votre communication pour s'adapter à ce nouveau contexte ?&lt;br /&gt;&lt;br /&gt;
Pour répondre à cette question stratégique, je vous propose deux dates et deux formules.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;(Dans les deux cas, vous aurez l'occasion de comprendre l'&amp;eacute;nigmatique illustration de ce billet !)&lt;/em&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Votre temps est compt&amp;eacute;&lt;/h2&gt;
&lt;p&gt;Si le temps vous fait d&amp;eacute;faut, l'agence Novius Paris et moi vous proposons un &lt;a href=&quot;http://rencontres.novius.com/rencontres-socialize-your-company/experience-utilisateur/presentation.html&quot; target=&quot;_blank&quot;&gt;atelier formation d'une matin&amp;eacute;e&lt;/a&gt;, mardi 22 mai. Ces quelques heures ensemble seront pour vous l'occasion de comprendre l'exp&amp;eacute;rience utilisateur et ses enjeux et d'en connaitre les r&amp;egrave;gles d'or et les derni&amp;egrave;res tendances. A travers un cas pratique, vous d&amp;eacute;couvrirez &amp;eacute;galement comment int&amp;eacute;grer l'exp&amp;eacute;rience utilisateur &amp;agrave; une strat&amp;eacute;gie de communication digitale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://rencontres.novius.com/rencontres-socialize-your-company/experience-utilisateur/inscription1.html&quot; target=&quot;_blank&quot;&gt;Inscrivez-vous !&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rencontres.novius.com/rencontres-socialize-your-company/experience-utilisateur/presentation.html&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/88.png&quot; alt=&quot;Ateier formation - Design d'exp&amp;eacute;rience utilisateur&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Une formation compl&amp;egrave;te d'une journ&amp;eacute;e&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.docschool.fr/index.php?le_num_rub=2&amp;amp;le_num_sous_rub=7&quot; target=&quot;_blank&quot;&gt;Une journ&amp;eacute;e enti&amp;egrave;re d&amp;eacute;di&amp;eacute;e &amp;agrave; l'exp&amp;eacute;rience utilisateur&lt;/a&gt;, voil&amp;agrave; ce que je vous propose dans le cadre de la Doc School le 6 juin, mais aussi le 10 octobre et le 12 d&amp;eacute;cembre. Nous disposerons du temps n&amp;eacute;cessaire pour aller au fond des choses et rentrer dans le concret. Comme pour toutes les formations Doc School, l'accent est mis sur la pratique, l'interactivit&amp;eacute; et le contact avec le terrain. Bref, une formation sur l'exp&amp;eacute;rience utilisateur qui est une vraie exp&amp;eacute;rience de formation !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.docschool.fr/index.php?le_num_rub=3&quot; target=&quot;_blank&quot;&gt;Inscrivez-vous !&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.docschool.fr/index.php?le_num_rub=2&amp;amp;le_num_sous_rub=7&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/89.png&quot; alt=&quot;Doc School - Concevoir une exp&amp;eacute;rience utilisateur web et mobile&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Mon, 30 Apr 2012 18:10:00 +0200</pubDate>
   </item>
   <item>
       <title>Bookmarklet pour afficher la grille de Foundation</title>
       <link>http://www.novius-labs.com/bookmarklet-pour-afficher-grille-foundation,46.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_46_vignette.png</img>
       <guid>http://www.novius-labs.com/bookmarklet-pour-afficher-grille-foundation,46.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_46_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Dans un &lt;a href=&quot;http://www.novius-labs.com/wif12-experience-utilisateur-experience-designer,45.html&quot;&gt;récent article&lt;/a&gt;, je vous parlais de in-browser prototyping. Si vous utilisez cette méthode et plus particulièrement Foundation, le bookmarklet que j'ai créé pourrait vous intéresser.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;strong&gt;&lt;a href=&quot;http://alefeuvre.github.com/foundation-grid-displayer/&quot; target=&quot;_blank&quot;&gt;Installer le bookmarklet&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le bookmarklet est tr&amp;egrave;s simple, il vous permet d'afficher la grille pour un site bas&amp;eacute; sur le &lt;a href=&quot;http://foundation.zurb.com/&quot; target=&quot;_blank&quot;&gt;framework open source Foundation&lt;/a&gt;. En phase de prototypage, c'est particuli&amp;egrave;rement pratique, on n'a pas &amp;agrave; regarder le code pour v&amp;eacute;rifier si une div est sur trois ou quatre colonnes. Ca permet aussi de v&amp;eacute;rifier les alignements.&lt;/p&gt;
&lt;p&gt;La grille peut &amp;ecirc;tre param&amp;eacute;tr&amp;eacute;e pour s'adapter &amp;agrave; tous les graphismes (couleur et opacit&amp;eacute; des lignes, z-index).&lt;/p&gt;
&lt;p&gt;Ce bookmarklet comme Foundation sont sous license MIT. Les sources sont disponibles &lt;a href=&quot;http://github.com/alefeuvre/foundation-grid-displayer/&quot; target=&quot;_blank&quot;&gt;sur GitHub&lt;/a&gt;, n'h&amp;eacute;sitez pas &amp;agrave; le &lt;em&gt;forker&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Voici un exemple avec le site Backup Train r&amp;eacute;alis&amp;eacute; dans le cadre du &lt;a href=&quot;http://www.novius-labs.com/wif12-experience-utilisateur-experience-designer,45.html&quot; target=&quot;_blank&quot;&gt;WIF12&lt;/a&gt; :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/87.png&quot; alt=&quot;Foundation grid displayer&quot; /&gt;&lt;/p&gt;
&lt;br /&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Tue, 03 Apr 2012 14:03:00 +0200</pubDate>
   </item>
   <item>
       <title>Tutoriel FuelPHP #6 : L'ORM, gestion des relations</title>
       <link>http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_44_vignette.png</img>
       <guid>http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_44_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Cet article, sans être une suite directe, s'inscrit dans la continuité des tutoriels réalisés par Julian et Sébastien. L'objectif de ce tutoriel est d'en apprendre plus sur l'ORM de FuelPHP, afin d'en comprendre les mécanismes principaux. Il s'inscrit dans le cadre de la réalisation d'une application de gestion d'un catalogue de produits, qui sera motorisée sous &lt;a href=&quot;http://www.novius-os.org&quot; target=&quot;_blank&quot;&gt;Novius OS&lt;/a&gt; (CMS open source basé sur FuelPHP).&lt;br /&gt;&lt;br /&gt;
Pour ce tutoriel, on prendra l'exemple plus simple d'un carnet d'adresses.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Mise en place du projet&lt;/h2&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;&amp;#65279;Sommaire du tutoriel&lt;br /&gt;&lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html&quot; target=&quot;_blank&quot;&gt;Choix du framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot; target=&quot;_blank&quot;&gt;Mise en place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot; target=&quot;_blank&quot;&gt;Cr&amp;eacute;ation d'un projet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot; target=&quot;_blank&quot;&gt;Application type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html&quot; target=&quot;_blank&quot;&gt;Cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;L'ORM, gestion des relations&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;h3&gt;Pr&amp;eacute;ambule&lt;/h3&gt;
&lt;p&gt;Bien qu'il soit  recommand&amp;eacute; d'avoir suivi les pr&amp;eacute;c&amp;eacute;dents tutoriels sur FuelPHP, celui-ci  est ind&amp;eacute;pendant. Pour ceux qui auraient aim&amp;eacute; reprendre &lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot; target=&quot;_blank&quot;&gt;leur pr&amp;eacute;c&amp;eacute;dent  projet&lt;/a&gt;, vous verrez ci-dessous pourquoi il est pr&amp;eacute;f&amp;eacute;rable de commencer  un nouveau projet.&lt;/p&gt;
&lt;p&gt;Comme pour les tutoriels pr&amp;eacute;c&amp;eacute;dents, on part du principe que vous  utilisez MySQL et le logiciel de gestion de bases de donn&amp;eacute;es phpMyAdmin.&lt;/p&gt;
&lt;h3&gt;Cr&amp;eacute;ation du projet et des premi&amp;egrave;res classes&lt;/h3&gt;
&lt;p&gt;Pour  aller plus vite et pour vous &amp;eacute;pargner des lignes de codes, on va  utiliser la commande &lt;span class=&quot;inline-code&quot;&gt;oil&lt;/span&gt;. On commence donc par cr&amp;eacute;er le projet :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code270&quot; class=&quot;cm-s-default&quot;&gt;oil create addressbook&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;N'oubliez  pas de cr&amp;eacute;er la base donn&amp;eacute;es &lt;span class=&quot;inline-code&quot;&gt;address_book&lt;/span&gt; qui sera associ&amp;eacute;e &amp;agrave; votre  projet et de configurer votre projet (cf. tutoriels &lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot; target=&quot;_blank&quot;&gt;#2&lt;/a&gt; et &lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot; target=&quot;_blank&quot;&gt;#3&lt;/a&gt;). Ne pas  oublier de d&amp;eacute;commenter la ligne &lt;span class=&quot;inline-code&quot;&gt;//'Orm'&lt;/span&gt;, de la liste des packages dans  le fichier &lt;span class=&quot;inline-code&quot;&gt;fuel/app/config/config.php&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;On va ensuite ajouter au  projet l'&amp;eacute;l&amp;eacute;ment principal du carnet d'adresse : le contact. On se place  donc dans le dossier du projet, puis on ex&amp;eacute;cute les commandes suivantes :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code271&quot; class=&quot;cm-s-default&quot;&gt;php oil g model contact name:string surname:string tel:string email:string address:text
php oil refine migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Vous  l'aurez peut-&amp;ecirc;tre remarqu&amp;eacute;, contrairement &amp;agrave; la commande utilis&amp;eacute;e lors  du tutoriel #3, celle-ci n'utilise pas le CRUD. Comme expliqu&amp;eacute; dans ce  m&amp;ecirc;me tutoriel, la cons&amp;eacute;quence principale vient du fait que le mod&amp;egrave;le  g&amp;eacute;n&amp;eacute;r&amp;eacute; n'&amp;eacute;tendra pas le &lt;span class=&quot;inline-code&quot;&gt;Model_Crud&lt;/span&gt;, mais le mod&amp;egrave;le de l'ORM. &amp;Eacute;tendre le  model de l'ORM de FuelPHP est la condition qui va ensuite permettre de  g&amp;eacute;rer des relations. C'est d'ailleurs la raison principale qui fait que  le projet pr&amp;eacute;c&amp;eacute;dent ne permettait pas de travailler sur ces questions !&lt;/p&gt;
&lt;p&gt;&amp;Agrave; ce stade je  vous conseille d'ouvrir votre &amp;eacute;diteur, et vous pouvez commencer par  constater que votre mod&amp;egrave;le &amp;eacute;tend bien le &lt;span class=&quot;inline-code&quot;&gt;Model&lt;/span&gt; de l'ORM :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code272&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
use Orm\Model;

class Model_Contact extends Model
{
    protected static $_properties = array(
        'id',
        'name',
        'surname',
        'tel',
        'email',
        'address',
        'created_at',
        'updated_at',
    );

    protected static $_observers = array(
        'Orm\Observer_CreatedAt' =&amp;gt; array(
            'events' =&amp;gt; array('before_insert'),
            'mysql_timestamp' =&amp;gt; false,
        ),
        'Orm\Observer_UpdatedAt' =&amp;gt; array(
            'events' =&amp;gt; array('before_save'),
            'mysql_timestamp' =&amp;gt; false,
        ),
    );

}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il ne vous reste qu'&amp;agrave; g&amp;eacute;n&amp;eacute;rer les deux autres mod&amp;egrave;les qui d&amp;eacute;finiront votre application :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code279&quot; class=&quot;cm-s-default&quot;&gt;php oil g model profile contact_id:int title:string description:text hobbies:string
php oil g model category parent_id:int title:string description:text
php oil refine migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Du fait d'avoir utiliser la commande&amp;nbsp;&lt;span class=&quot;inline-code&quot;&gt;oil generate model&lt;/span&gt;&amp;nbsp;plut&amp;ocirc;t que &lt;span class=&quot;inline-code&quot;&gt;oil generate scaffold, v&lt;/span&gt;ous aurez remarqu&amp;eacute; que les contr&amp;ocirc;leurs et vues associ&amp;eacute;s n'ont pas &amp;eacute;t&amp;eacute; g&amp;eacute;n&amp;eacute;r&amp;eacute;s. Pour manipuler nos mod&amp;egrave;les, on utilisera la console de FuelPHP ! Cet outil a le m&amp;eacute;rite de nous permettre d'effectuer des op&amp;eacute;rations sur  les mod&amp;egrave;les sans avoir &amp;agrave; configurer les vues et les contr&amp;ocirc;leurs  associ&amp;eacute;s. Cela va donc nous permettre de rester concentr&amp;eacute; sur l'objet de  ce tutoriel : l'ORM et les relations.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Cr&amp;eacute;ation des relations&lt;/h2&gt;
&lt;p&gt;Afin d'essayer d'&amp;ecirc;tre le plus exhaustif possible, on va mettre en place les 3 types principaux de relations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;many to many&quot;&lt;/li&gt;
&lt;li&gt;&quot;has many&quot; (et son compl&amp;eacute;ment &quot;belongs to&quot;)&lt;/li&gt;
&lt;li&gt;&quot;has one&quot; (idem)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp;
&lt;h2&gt;Relation &quot;Has One&quot;&lt;/h2&gt;
&lt;p&gt;Commen&amp;ccedil;ons par la relation la plus simple.&lt;/p&gt;
&lt;p&gt;Un contact pourra ainsi &amp;ecirc;tre associ&amp;eacute; &amp;agrave; un profil. Imaginons que vous souhaitiez &amp;eacute;toffer un peu les informations dont vous disposez sur certains contacts. Plut&amp;ocirc;t que d'avoir un mod&amp;egrave;le de contacts avec des champs suppl&amp;eacute;mentaires et entra&amp;icirc;ner la cr&amp;eacute;ation de contacts incomplets, on ajoute une relation vers un profil qui compl&amp;egrave;tera le contact. On va pr&amp;eacute;ciser cette relation au niveau du mod&amp;egrave;le.&lt;/p&gt;
&lt;p&gt;Pour le contact, il suffit d'ajouter l'attribut &lt;span class=&quot;inline-code&quot;&gt;$_has_one&lt;/span&gt;&amp;nbsp;comme ceci :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code282&quot; class=&quot;cm-s-default&quot;&gt;protected static $_has_one = array(
    'profile' =&amp;gt; array(
	'key_from' =&amp;gt; 'id',
	'model_to' =&amp;gt; 'Model_Profile',
	'key_to' =&amp;gt; 'contact_id',
	'cascade_save' =&amp;gt; true,
	'cascade_delete' =&amp;gt; true,
    )
);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On remarque que, puisque le profil n'a pas d'existence l&amp;eacute;gitime sans un contact, la sauvegarde du contact entra&amp;icirc;ne n&amp;eacute;cessairement la sauvegarde du profil. Il en va de m&amp;ecirc;me pour la suppression.&lt;/p&gt;
&lt;p&gt;En compl&amp;eacute;ment, on ajoute sur le mod&amp;egrave;le du profil l'attribut suivant :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code283&quot; class=&quot;cm-s-default&quot;&gt;protected static $_belongs_to = array(
    'contact' =&amp;gt; array(
	'key_from' =&amp;gt; 'contact_id',
	'model_to' =&amp;gt; 'Model_Contact',
	'key_to' =&amp;gt; 'id',
	'cascade_save' =&amp;gt; false,
	'cascade_delete' =&amp;gt; false,
    )
);&lt;/code&gt;&lt;/pre&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On remarque que, pour le profil, sa suppression ne doit pas entra&amp;icirc;ner la suppression du contact et ce pour deux raisons :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On peut envisager que le contact n'ait pas de profil,&lt;/li&gt;
&lt;li&gt;Mais surtout le seul moyen de mettre &amp;agrave; jour une relation est de supprimer cette relation avant de la r&amp;eacute;affecter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On va maintenant pouvoir commencer &amp;agrave; utiliser la console.&lt;/p&gt;
&lt;p&gt;Pour bien comprendre les m&amp;eacute;canismes de l'ORM, il peut &amp;ecirc;tre int&amp;eacute;ressant d'observer les requ&amp;ecirc;tes r&amp;eacute;alis&amp;eacute;es par l'ORM. La d&amp;eacute;marche pour MySQL sous Ubuntu est expliqu&amp;eacute;e &lt;a href=&quot;http://www.howtogeek.com/howto/database/monitor-all-sql-queries-in-mysql/&quot; target=&quot;_blank&quot;&gt;ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dans votre terminal, &amp;agrave; la racine de votre projet, ex&amp;eacute;cutez la commande suivante (attention : la console n'est pas compl&amp;egrave;tement stable. En cas d'&amp;eacute;chec lors de l'ex&amp;eacute;cution de votre commande, il vous faudra la relancer et vous n'aurez plus acc&amp;egrave;s &amp;agrave; votre historique, ni &amp;agrave; vos variables...) :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code285&quot; class=&quot;cm-s-default&quot;&gt;oil console&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On commence par cr&amp;eacute;er un contact, on lui affecte un profil, avant de valider la cr&amp;eacute;ation et donc de l'enregistrer en base :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code286&quot; class=&quot;cm-s-default&quot;&gt;$model = new Model_Contact(array('name'=&amp;gt;'ALBERT', 'surname'=&amp;gt; 'Victor', 'tel'=&amp;gt; '0123456789', 'email'=&amp;gt; 'victor@plop.fr', 'address'=&amp;gt; '0 rue du tutoriel 00000 TUTO'));
$model-&amp;gt;profile = new Model_Profile(array('title'=&amp;gt; 'ecommerce', 'description'=&amp;gt; 'works on a project for a few months', 'hobbies'=&amp;gt; 'climbing'));
$model-&amp;gt;save();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut alors voir les requ&amp;ecirc;tes associ&amp;eacute;es :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code288&quot; class=&quot;cm-s-default&quot;&gt;INSERT INTO `contacts` (`name`, `surname`, `tel`, `email`, `address`, `created_at`, `updated_at`) VALUES ('ALBERT', 'Victor', '0123456789', 'victor@plop.fr', '0 rue du tutoriel 00000 TUTO', 1333034478, 1333034478)

INSERT INTO `profiles` (`contact_id`, `title`, `description`, `hobbies`, `created_at`, `updated_at`) VALUES (1, 'ecommerce', 'works on a project for a few months', 'climbing', 1333034478, 1333034478)&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;L'ajout du profil se fait en renseignant la relation. En r&amp;eacute;alisant l'appel &amp;agrave; la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;save()&lt;/span&gt;&amp;nbsp;sur le contact, le&amp;nbsp;&lt;span class=&quot;inline-code&quot;&gt;cascade_save =&amp;gt; true&lt;/span&gt; d&amp;eacute;fini avec la relation suffit &amp;agrave; sauvegarder le profil dans la base.&lt;/p&gt;
&lt;p&gt;La mise &amp;agrave; jour de vos donn&amp;eacute;es peut ainsi se faire uniquement via le contact :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code289&quot; class=&quot;cm-s-default&quot;&gt;$model-&amp;gt;profile-&amp;gt;hobbies = 'cinema';
$model-&amp;gt;save()
$model-&amp;gt;email = 'albert@plop.fr';
$model-&amp;gt;save();
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code290&quot; class=&quot;cm-s-default&quot;&gt;UPDATE `profiles` SET `contact_id` = 1, `title` = 'ecommerce', `description` = 'works on a project for a few months', `hobbies` = 'cinema', `created_at` = 1333034478, `updated_at` = 1333034923 WHERE `profile_id` = 1 LIMIT 1

UPDATE `contacts` SET `name` = 'ALBERT', `surname` = 'Victor', `tel` = '0123456789', `email` = 'albert@plop.fr', `address` = '0 rue du tutoriel 00000 TUTO', `created_at` = 1333034478, `updated_at` = 1333034979 WHERE `contact_id` = 1 LIMIT 1&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;La suppression est un peu plus compliqu&amp;eacute;e : appeler la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;delete()&lt;/span&gt;&amp;nbsp;sur le profil supprime les donn&amp;eacute;es en base, mais ne d&amp;eacute;truit pas l'objet PHP. Si on appelle la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;save()&lt;/span&gt;&amp;nbsp;par la suite, l'ORM consid&amp;egrave;re que la relation existe toujours et tente de sauvegarder les donn&amp;eacute;es. Puisque la relation est th&amp;eacute;oriquement d&amp;eacute;truite, le champ &lt;span class=&quot;inline-code&quot;&gt;contact_id&lt;/span&gt;&amp;nbsp;est&amp;nbsp;&lt;span class=&quot;inline-code&quot;&gt;null&lt;/span&gt; et si la base ne le permet pas (comme c'est le cas par d&amp;eacute;faut) cela g&amp;eacute;n&amp;egrave;re une erreur. Il faut donc en plus affecter &lt;span class=&quot;inline-code&quot;&gt;null&lt;/span&gt; &amp;agrave; la relation ; c'est par ce m&amp;eacute;canisme que FuelPHP d&amp;eacute;truit effectivement l'objet, avant d'appliquer la suppression en base via la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;save()&lt;/span&gt; de votre contact.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code292&quot; class=&quot;cm-s-default&quot;&gt;$model-&amp;gt;profile-&amp;gt;delete();
$model-&amp;gt;profile = null;
$model-&amp;gt;save()
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code291&quot; class=&quot;cm-s-default&quot;&gt;SELECT `t0`.`contact_id` AS `t0_c0`, `t0`.`name` AS `t0_c1`, `t0`.`surname` AS `t0_c2`, `t0`.`tel` AS `t0_c3`, `t0`.`email` AS `t0_c4`, `t0`.`address` AS `t0_c5`, `t0`.`created_at` AS `t0_c6`, `t0`.`updated_at` AS `t0_c7` FROM `contacts` AS `t0` WHERE `t0`.`contact_id` = 1 LIMIT 1
DELETE FROM `profiles` WHERE `profile_id` = 1 LIMIT 1

UPDATE `contacts` SET `name` = 'ALBERT', `surname` = 'Victor', `tel` = '0123456789', `email` = 'albert@plop.fr', `address` = '0 rue du tutoriel 00000 TUTO', `created_at` = 1333035504, `updated_at` = 1333036579 WHERE `contact_id` = 1 LIMIT 1
SELECT `t0`.`profile_id` AS `t0_c0`, `t0`.`contact_id` AS `t0_c1`, `t0`.`title` AS `t0_c2`, `t0`.`description` AS `t0_c3`, `t0`.`hobbies` AS `t0_c4`, `t0`.`created_at` AS `t0_c5`, `t0`.`updated_at` AS `t0_c6` FROM `profiles` AS `t0` WHERE `t0`.`profile_id` = '1' LIMIT 1&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Relation &quot;Has Many&quot;&lt;/h2&gt;
&lt;p&gt;On va maintenant travailler avec les cat&amp;eacute;gories. Envisageons l'utilisation suivante : chaque contact pourra par la suite &amp;ecirc;tre associ&amp;eacute; &amp;agrave; une ou plusieurs cat&amp;eacute;gories. Ces cat&amp;eacute;gories sont hi&amp;eacute;rarchis&amp;eacute;es : on peut envisager une cat&amp;eacute;gorie &quot;Travail&quot; et des sous-cat&amp;eacute;gories &quot;R&amp;amp;D&quot;, &quot;Marketing&quot;. On pourrait classer ses contacts de mani&amp;egrave;re suffisamment pr&amp;eacute;cise pour pouvoir :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;les trouver rapidement&lt;/li&gt;
&lt;li&gt;les filtrer rapidement&lt;/li&gt;
&lt;li&gt;retrouver le contexte dans lequel on les a connus&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ce type de relation peut donc &amp;ecirc;tre mis en place avec la relation &quot;Has Many&quot;. On ajoute donc les deux propri&amp;eacute;t&amp;eacute;s suivantes au mod&amp;egrave;le de la cat&amp;eacute;gorie :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code293&quot; class=&quot;cm-s-default&quot;&gt;    protected static $_has_many = array(
        'variants' =&amp;gt; array(
            'key_from' =&amp;gt; 'id',
            'model_to' =&amp;gt; 'Model_Category',
            'key_to' =&amp;gt; 'parent_id',
            'cascade_save' =&amp;gt; true,
            'cascade_delete' =&amp;gt; true,
        )
    );

    protected static $_belongs_to = array(
        'parent' =&amp;gt; array(
            'key_from' =&amp;gt; 'parent_id',
            'model_to' =&amp;gt; 'Model_Category',
            'key_to' =&amp;gt; 'id',
            'cascade_save' =&amp;gt; true,
            'cascade_delete' =&amp;gt; false,
        )
    );&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On remarque que le &lt;span class=&quot;inline-code&quot;&gt;cascade_delete&lt;/span&gt; est &lt;span class=&quot;inline-code&quot;&gt;true&lt;/span&gt; dans le sens &quot;parent -&amp;gt; enfant&quot;, et &lt;span class=&quot;inline-code&quot;&gt;false&lt;/span&gt; dans le &quot;sens enfant -&amp;gt; parent&quot;. Cela se comprend facilement : &quot;Travail&quot; reste l&amp;eacute;gitime si on d&amp;eacute;cide de supprimer &quot;Marketing&quot; alors que si on d&amp;eacute;cide de supprimer &quot;Travail&quot;, c'est qu'on ne souhaite plus associer de contacts au &quot;Travail&quot; et &amp;agrave; toutes ses d&amp;eacute;clinaisons.&lt;/p&gt;
&lt;p&gt;On va commencer par pr&amp;eacute;ciser que le champ &lt;span class=&quot;inline-code&quot;&gt;parent_id&lt;/span&gt; peut &amp;ecirc;tre &lt;span class=&quot;inline-code&quot;&gt;null&lt;/span&gt;. Plusieurs solutions sont possibles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l'indiquer directement dans la base via votre gestionnaire de base de donn&amp;eacute;es ;&lt;/li&gt;
&lt;li&gt;ou modifier la fonction &lt;span class=&quot;inline-code&quot;&gt;up()&lt;/span&gt; de la migration correspondant &amp;agrave; la cr&amp;eacute;ation des cat&amp;eacute;gories :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code294&quot; class=&quot;cm-s-default&quot;&gt;public function up()
	{
		\DBUtil::create_table('categories', array(
			'id' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int', 'auto_increment' =&amp;gt; true),
            'parent_id' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int', 'null' =&amp;gt; true),
			'title' =&amp;gt; array('constraint' =&amp;gt; 255, 'type' =&amp;gt; 'varchar'),
			'description' =&amp;gt; array('type' =&amp;gt; 'text'),
			'created_at' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int'),
			'updated_at' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int'),
		), array('id'));
	}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code295&quot; class=&quot;cm-s-default&quot;&gt;oil refine migrate:down
oil refine migrate:up&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On va ensuite v&amp;eacute;rifier le bon comportement des cat&amp;eacute;gories et des d&amp;eacute;clinaisons :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code296&quot; class=&quot;cm-s-default&quot;&gt;$parent = Model_Category::forge(array('title' =&amp;gt; 'Friends', 'description' =&amp;gt; 'People I like to see at anytime'));
$parent-&amp;gt;save();
$parent-&amp;gt;variants[] = Model_Category::forge(array('title' =&amp;gt; 'School', 'description' =&amp;gt; 'People I met when I was a student'));
$parent-&amp;gt;variants[] = Model_Category::forge(array('title' =&amp;gt; 'Childhood', 'description' =&amp;gt; 'People I know since I was a kid'));
$parent-&amp;gt;save();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code297&quot; class=&quot;cm-s-default&quot;&gt;INSERT INTO `categories` (`parent_id`, `title`, `description`, `created_at`, `updated_at`) VALUES (null, 'Friends', 'People I like to see at anytime', 1333354737, 1333354737)

UPDATE `categories` SET `parent_id` = null, `title` = 'Friends', `description` = 'People I like to see at anytime', `created_at` = 1333354737, `updated_at` = 1333354791 WHERE `id` = 1 LIMIT 1
INSERT INTO `categories` (`parent_id`, `title`, `description`, `created_at`, `updated_at`) VALUES (1, 'School', 'People I met when I was a student', 1333354791, 1333354791)
INSERT INTO `categories` (`parent_id`, `title`, `description`, `created_at`, `updated_at`) VALUES (1, 'Childhood', 'People I know since I was a kid', 1333354791, 1333354791)&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La cl&amp;eacute; du tableau qui g&amp;egrave;re les relations correspond &amp;agrave; l'identifiant de la cat&amp;eacute;gorie associ&amp;eacute;e :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code298&quot; class=&quot;cm-s-default&quot;&gt;&amp;gt;&amp;gt;&amp;gt; $parent-&amp;gt;variants
array (
  2 =&amp;gt; 
  Model_Category::__set_state(array(
     '_is_new' =&amp;gt; false,
     '_frozen' =&amp;gt; false,
     '_data' =&amp;gt; 
    array (
      'title' =&amp;gt; 'School',
      'description' =&amp;gt; 'People I met when I was a student',
      'parent_id' =&amp;gt; 1,
      'updated_at' =&amp;gt; 1333358505,
      'created_at' =&amp;gt; 1333358505,
      'id' =&amp;gt; 2,
    ),
     '_original' =&amp;gt; 
    array (
      'title' =&amp;gt; 'School',
      'description' =&amp;gt; 'People I met when I was a student',
      'parent_id' =&amp;gt; 1,
      'updated_at' =&amp;gt; 1333358505,
      'created_at' =&amp;gt; 1333358505,
      'id' =&amp;gt; 2,
    ),
     '_data_relations' =&amp;gt; 
    array (
    ),
     '_original_relations' =&amp;gt; 
    array (
    ),
     '_view' =&amp;gt; NULL,
     '_iterable' =&amp;gt; 
    array (
    ),
  )),
  3 =&amp;gt; 
  Model_Category::__set_state(array(
     '_is_new' =&amp;gt; false,
     '_frozen' =&amp;gt; false,
     '_data' =&amp;gt; 
    array (
      'title' =&amp;gt; 'Childhood',
      'description' =&amp;gt; 'People I know since I was a kid',
      'parent_id' =&amp;gt; 1,
      'updated_at' =&amp;gt; 1333358505,
      'created_at' =&amp;gt; 1333358505,
      'id' =&amp;gt; 3,
    ),
     '_original' =&amp;gt; 
    array (
      'title' =&amp;gt; 'Childhood',
      'description' =&amp;gt; 'People I know since I was a kid',
      'parent_id' =&amp;gt; 1,
      'updated_at' =&amp;gt; 1333358505,
      'created_at' =&amp;gt; 1333358505,
      'id' =&amp;gt; 3,
    ),
     '_data_relations' =&amp;gt; 
    array (
    ),
     '_original_relations' =&amp;gt; 
    array (
    ),
     '_view' =&amp;gt; NULL,
     '_iterable' =&amp;gt; 
    array (
    ),
  )),
)
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On peut ensuite modifier indiff&amp;eacute;remment toutes les cat&amp;eacute;gories, directement ou via la cat&amp;eacute;gorie parente :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code299&quot; class=&quot;cm-s-default&quot;&gt;$parent-&amp;gt;variants[2]-&amp;gt;description = 'Those I met when I was a student';
$parent-&amp;gt;save();
$child = Model_Category::find('first', array('where' =&amp;gt; array(array('title', 'Childhood'))));
$child-&amp;gt;description = 'Those I know since I was a child';
$child-&amp;gt;save();
$parent-&amp;gt;variants&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code300&quot; class=&quot;cm-s-default&quot;&gt;UPDATE `categories` SET `parent_id` = null, `title` = 'Friends', `description` = 'People I like to see at anytime', `created_at` = 1333358474, `updated_at` = 1333358676 WHERE `id` = 1 LIMIT 1
UPDATE `categories` SET `parent_id` = 1, `title` = 'School', `description` = 'Those I met when I was a student', `created_at` = 1333358505, `updated_at` = 1333358676 WHERE `id` = 2 LIMIT 1

UPDATE `categories` SET `parent_id` = '1', `title` = 'Childhood', `description` = 'Those I know since I was a child', `created_at` = '1333358505', `updated_at` = 1333358954 WHERE `id` = '3' LIMIT 1&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Pour limiter le nombre de requ&amp;ecirc;tes, il est donc pr&amp;eacute;f&amp;eacute;rable d'appeler la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;save()&lt;/span&gt;&amp;nbsp;directement sur l'objet modifi&amp;eacute;, mais il peut &amp;ecirc;tre bien pratique d'utiliser la sauvegarde r&amp;eacute;cursive.&lt;/p&gt;
&lt;p&gt;Note : on peut aussi appeler la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;save()&lt;/span&gt;&amp;nbsp;sur la relation en passant par la cat&amp;eacute;gorie parente :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code301&quot; class=&quot;cm-s-default&quot;&gt;$parent-&amp;gt;variants[3]-&amp;gt;description = 'Those I have known since my childhood';
$parent-&amp;gt;variants[3]-&amp;gt;save();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;La suppression des cat&amp;eacute;gories se fait selon le comportement pr&amp;eacute;vu, et comme pour la relation &quot;has one&quot;, il faut supprimer l'objet dans la base si on ne souhaite pas la r&amp;eacute;affecter ensuite :&lt;/p&gt;
&lt;p&gt;Remarque : La fonction &lt;span class=&quot;inline-code&quot;&gt;unset&lt;/span&gt;&amp;nbsp;est actuellement mal support&amp;eacute;e par la console, pour rectifier le probl&amp;egrave;me, on ajoute &lt;span class=&quot;inline-code&quot;&gt;false;&lt;/span&gt; avant l'appel.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code302&quot; class=&quot;cm-s-default&quot;&gt;$parent-&amp;gt;variants[3]-&amp;gt;delete();
false; unset($parent-&amp;gt;variants[3]);
$parent-&amp;gt;save();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez constater que votre table ne contient plus que la cat&amp;eacute;gorie principale &quot;Friends&quot; et la cat&amp;eacute;gorie secondaire &quot;School&quot;. En supprimant la cat&amp;eacute;gorie principale, la cat&amp;eacute;gorie secondaire sera &amp;eacute;galement supprim&amp;eacute;e :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code304&quot; class=&quot;cm-s-default&quot;&gt;$parent-&amp;gt;delete();
Model_Category::find('all')&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code305&quot; class=&quot;cm-s-default&quot;&gt;SELECT `t0`.`id` AS `t0_c0`, `t0`.`parent_id` AS `t0_c1`, `t0`.`title` AS `t0_c2`, `t0`.`description` AS `t0_c3`, `t0`.`created_at` AS `t0_c4`, `t0`.`updated_at` AS `t0_c5` FROM `categories` AS `t0` WHERE `t0`.`parent_id` = '1'
DELETE FROM `categories` WHERE `id` = '1' LIMIT 1
SELECT `t0`.`id` AS `t0_c0`, `t0`.`parent_id` AS `t0_c1`, `t0`.`title` AS `t0_c2`, `t0`.`description` AS `t0_c3`, `t0`.`created_at` AS `t0_c4`, `t0`.`updated_at` AS `t0_c5` FROM `categories` AS `t0` WHERE `t0`.`id` IS null LIMIT 1
SELECT `t0`.`id` AS `t0_c0`, `t0`.`parent_id` AS `t0_c1`, `t0`.`title` AS `t0_c2`, `t0`.`description` AS `t0_c3`, `t0`.`created_at` AS `t0_c4`, `t0`.`updated_at` AS `t0_c5` FROM `categories` AS `t0` WHERE `t0`.`parent_id` = '2'
DELETE FROM `categories` WHERE `id` = '2' LIMIT 1&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Relation &quot;Many to Many&quot;&lt;/h2&gt;
&lt;p&gt;Derni&amp;egrave;re relation &amp;agrave; mettre en place : affecter une &amp;agrave; plusieurs cat&amp;eacute;gories &amp;agrave; un ou plusieurs contacts.&lt;/p&gt;
&lt;p&gt;Pour enregistrer la relation, il faut une table d&amp;eacute;di&amp;eacute;e :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vous pouvez l'ajouter via votre gestionnaire de base de donn&amp;eacute;es ;&lt;/li&gt;
&lt;li&gt;Ou g&amp;eacute;n&amp;eacute;rer la migration suivante et effectuer la commande&amp;nbsp;&lt;span class=&quot;inline-code&quot;&gt;oil refine migrate&lt;/span&gt;. Le contenu de la migration est donn&amp;eacute; ci-dessous:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code id=&quot;code311&quot; class=&quot;cm-s-default&quot;&gt;php oil g migration create_contacts_categories&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code306&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php

namespace Fuel\Migrations;

class Create_contacts_categories
{
    public function up()
    {
        \DBUtil::create_table('contacts_categories', array(
            'contact_id' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int'),
            'category_id' =&amp;gt; array('constraint' =&amp;gt; 11, 'type' =&amp;gt; 'int'),
        ), array('contact_id', 'category_id'));
    }

    public function down()
    {
        \DBUtil::drop_table('contacts_categories');
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Il vous faut ensuite &amp;eacute;crire la relation sur vos mod&amp;egrave;les. Pour le contact :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code307&quot; class=&quot;cm-s-default&quot;&gt;    protected static $_many_many = array(
        'categories' =&amp;gt; array(
            'key_from' =&amp;gt; 'id',
            'key_through_from' =&amp;gt; 'contact_id',
            'table_through' =&amp;gt; 'contacts_categories',
            'key_through_to' =&amp;gt; 'category_id',
            'model_to' =&amp;gt; 'Model_Category',
            'key_to' =&amp;gt; 'id',
            'cascade_save' =&amp;gt; false,
            'cascade_delete' =&amp;gt; false,
        )
    );&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Pour la cat&amp;eacute;gorie :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code308&quot; class=&quot;cm-s-default&quot;&gt;    protected static $_many_many = array(
        'contacts' =&amp;gt; array(
            'key_from' =&amp;gt; 'id',
            'key_through_from' =&amp;gt; 'category_id',
            'table_through' =&amp;gt; 'contacts_categories',
            'key_through_to' =&amp;gt; 'contact_id',
            'model_to' =&amp;gt; 'Model_Contact',
            'key_to' =&amp;gt; 'id',
            'cascade_save' =&amp;gt; true,
            'cascade_delete' =&amp;gt; false,
        )
    );&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Vous pouvez maintenant cr&amp;eacute;er vos contacts et cat&amp;eacute;gories et tester les relations :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code309&quot; class=&quot;cm-s-default&quot;&gt;$colleague = Model_Contact::forge(array('name' =&amp;gt; 'LEFEUVRE', 'surname' =&amp;gt; 'Antoine', 'tel' =&amp;gt; '0123456789', 'email' =&amp;gt; 'lefeuvre@plop.fr', 'address'=&amp;gt; '0 rue du tutoriel 00000 TUTO'));
$friend = Model_Contact::forge(array('name' =&amp;gt; 'DUPONT', 'surname' =&amp;gt; 'Jean', 'tel' =&amp;gt; '0987654321', 'email' =&amp;gt; 'jean@plop.fr', 'address' =&amp;gt; '0 rue de la paix 00000 TUTO'));
$colleague-&amp;gt;save();
$friend-&amp;gt;save();
$category = Model_Category::forge(array('title' =&amp;gt; 'Friends', 'description' =&amp;gt; 'People I like to see at anytime'));
$category-&amp;gt;save();
$work = Model_Category::forge(array('title' =&amp;gt; 'Work', 'description' =&amp;gt; 'People I met at work'));
$work-&amp;gt;save();
$work-&amp;gt;variants[] = Model_Category::forge(array('title' =&amp;gt; 'Novius', 'description' =&amp;gt; 'People I met at Novius'));
$work-&amp;gt;variants[] = Model_Category::forge(array('title' =&amp;gt; 'Former', 'description' =&amp;gt; 'People I met when working in a former enterprise'));
$work-&amp;gt;save();

$novius = Model_Category::find('first', array('where' =&amp;gt; array(array('title', 'Novius'))));
$colleague-&amp;gt;categories[] = $novius;
$colleague-&amp;gt;save();
$friend-&amp;gt;categories[] = Model_Category::find('first', array('where' =&amp;gt; array(array('title', 'Friends'))));
$friend-&amp;gt;categories[] = Model_Category::find('first', array('where' =&amp;gt; array(array('title', 'Former'))));;
$friend-&amp;gt;save();
Model_Contact::find('all')&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
Exemple : supprimer la cat&amp;eacute;gorie principale et v&amp;eacute;rifier qu'elle n'est plus affect&amp;eacute;e aux contacts (on la retrouve sur les&amp;nbsp;&lt;span class=&quot;inline-code&quot;&gt;_original_relations&lt;/span&gt; mais a disparu des &lt;span class=&quot;inline-code&quot;&gt;_data_relations&lt;/span&gt;) :
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code310&quot; class=&quot;cm-s-default&quot;&gt;$work-&amp;gt;delete();
Model_Contact::find('all')&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Bilan&lt;/h2&gt;
&lt;p&gt;Vous &amp;ecirc;tes maintenant capable de mettre en place les trois types de relations principaux. Il ne vous reste qu'&amp;agrave; les configurer selon vos besoins, et vous pourrez &amp;eacute;galement tester les nombreuses possibilit&amp;eacute;s associ&amp;eacute;es &amp;agrave; la fonction &lt;span class=&quot;inline-code&quot;&gt;find&lt;/span&gt; (expliqu&amp;eacute;es succintement sur &lt;a href=&quot;http://docs.fuelphp.com/packages/orm/relations/intro.html&quot; target=&quot;_blank&quot;&gt;cette page&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Pour info : le sch&amp;eacute;ma illustrant ce tutoriel provient provient de &lt;a href=&quot;http://danhartshorn.com/2011/12/object-relational-mapping-wikipedia-the-free-encyclopedia/&quot; target=&quot;_blank&quot;&gt;cette page&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Victor Albert </dc:creator>
       <pubDate>Tue, 03 Apr 2012 08:53:00 +0200</pubDate>
   </item>
   <item>
       <title>WIF12 : expérience utilisateur, expérience de designer</title>
       <link>http://www.novius-labs.com/wif12-experience-utilisateur-experience-designer,45.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_45_vignette.png</img>
       <guid>http://www.novius-labs.com/wif12-experience-utilisateur-experience-designer,45.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_45_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Le 16 mars, se sont déroulées les présélections du concours du Festival international du design interactif de Limoges, mieux connu sous le nom de WIF (voire #wif12 pour les tweetos&amp;nbsp;!). 24 heures chrono pour réaliser, en équipe de quatre maximum, un prototype d'interface ou service innovant. Cette année, le sujet de la compétition était &quot;Design interactif et développement durable&quot;.&lt;br /&gt;&lt;br /&gt;
Une équipe de novusiens faisait partie des 200 équipes qui, à travers le monde, ont pris part au challenge. On a beaucoup parlé expérience utilisateur et, pourtant, j'en retiens une expérience de designer.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;La team Novius &amp;eacute;tait constitu&amp;eacute;e d'un graphiste (Fr&amp;eacute;d&amp;eacute;ric Jacquemoud), deux d&amp;eacute;veloppeurs (Julien Guyomard et S&amp;eacute;bastien Drouyer) et d'un UX designer (votre serviteur). Notre r&amp;eacute;alisation porte le nom de &lt;a href=&quot;http://webdesign-festival.com/2012/equipes/preselection/team_novius/index.html&quot; target=&quot;_blank&quot;&gt;Backup Train&lt;/a&gt;. Il s'agit d'un prototype de service sur smartphone et mur intelligent (type tweetwall). Son objectif est d'aider les usagers des transports publics &amp;agrave; trouver facilement et rapidement une solution de repli, en cas de perturbation du trafic.&lt;/p&gt;
&lt;p&gt;Je vous laisse &lt;a href=&quot;http://webdesign-festival.com/2012/equipes/preselection/team_novius/site/index.html&quot; target=&quot;_blank&quot;&gt;d&amp;eacute;couvrir notre projet&lt;/a&gt;. Je vais plut&amp;ocirc;t vous parler de sa r&amp;eacute;alisation en marche forc&amp;eacute;e et des enseignements que j'en tire.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;&lt;em&gt;In-browser prototyping&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;En plus de dix ann&amp;eacute;es de web design, j'ai utilis&amp;eacute; de nombreuses techniques de prototypage : maquettes ou wireframes cliquables (avec de bonnes vieilles images mapp&amp;eacute;es ou, plus r&amp;eacute;cemment, &lt;a href=&quot;http://www.invisionapp.com/&quot; target=&quot;_blank&quot;&gt;InVision&lt;/a&gt;), logiciels d&amp;eacute;di&amp;eacute;s (Balsamiq, Axure), vid&amp;eacute;os de d&amp;eacute;monstration, Flash, etc. Depuis plusieurs mois, je m'int&amp;eacute;resse surtout &amp;agrave; ce que ZURB appelle le &lt;em&gt;&lt;a href=&quot;http://www.zurb.com/article/876/quick-and-dirty-design-critiques-with-in-&quot; target=&quot;_blank&quot;&gt;in-browser prototyping&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En quoi consiste cette m&amp;eacute;thode ? Il s'agit d'attaquer le code le plus t&amp;ocirc;t possible, sans pour autant perdre en rapidit&amp;eacute; d'ex&amp;eacute;cution ce qui est essentiel pour le prototypage. Concr&amp;egrave;tement, on utilise un inspecteur de code (Firebug) et un &lt;em&gt;boilerplate&lt;/em&gt; comme &lt;a href=&quot;http://foundation.zurb.com&quot; target=&quot;_blank&quot;&gt;Foundation&lt;/a&gt;, &lt;a href=&quot;http://twitter.github.com/bootstrap/&quot; target=&quot;_blank&quot;&gt;Twitter Bootstrap&lt;/a&gt; ou encore &lt;a href=&quot;http://www.99lime.com/&quot; target=&quot;_blank&quot;&gt;HTML KickStart&lt;/a&gt;. Ce sont de vrais kits &amp;agrave; prototype. Ils fournissent des styles de base, une grille typographique, des &amp;eacute;l&amp;eacute;ments d'UI (menus, formulaires), des plugins jQuery (diaporamas, fen&amp;ecirc;tres modales), j'en passe.&lt;/p&gt;
&lt;p&gt;Bref, la seule installation &amp;agrave; faire est celle du &lt;em&gt;boilerplate&lt;/em&gt;, on dispose alors de tous les &amp;eacute;l&amp;eacute;ments n&amp;eacute;cessaires pour prototyper. Cerise sur le g&amp;acirc;teau, ces &lt;em&gt;boilerplates &lt;/em&gt;sont tous &amp;agrave; l'heure du &lt;strong&gt;multi-devices&lt;/strong&gt;, contrairement &amp;agrave; la plupart des autres techniques de prototypage. Ils sont ainsi en ad&amp;eacute;quation avec des m&amp;eacute;thodes &lt;a href=&quot;http://futurefriend.ly&quot; target=&quot;_blank&quot;&gt;future-friendly&lt;/a&gt;, comme le design universel et Mobile First.&lt;/p&gt;
&lt;p&gt;Pour le WIF, l&amp;agrave; o&amp;ugrave; le &lt;em&gt;in-browser prototyping&lt;/em&gt; s'est r&amp;eacute;v&amp;eacute;l&amp;eacute; d&amp;eacute;cisif, c'est qu'il n'y a &lt;strong&gt;pas de rupture entre le prototype et le produit final&lt;/strong&gt;. Il n'y a pas &amp;agrave; int&amp;eacute;grer des maquettes, le prototype &amp;eacute;volue naturellement en un site ou application, au fur et &amp;agrave; mesure qu'on l'affine, qu'on rentre dans le d&amp;eacute;tail. C'est ce qui s'est pass&amp;eacute; pour le site Backup Train : le site est le prototype. Nous aurions difficilement pu nous permettre de r&amp;eacute;aliser un site plus une application mobile en 24 heures, si nous avions choisi une autre technique de prototypage.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;R&amp;eacute;flechir longuement, produire vite&lt;/h2&gt;
&lt;p&gt;La question s'est tout de suite pos&amp;eacute;e : doit-on se fixer des deadlines interm&amp;eacute;diaires, &amp;eacute;tape par &amp;eacute;tape, pour tenir LA deadline, celle des 24 heures ? Nous sommes tomb&amp;eacute;s d'accord, pas de limite &amp;agrave; la r&amp;eacute;flexion. Ce n'&amp;eacute;tait pas pour moi une d&amp;eacute;cision &amp;eacute;vidente. J'&amp;eacute;tais tent&amp;eacute; de dire : imposons une deadline, de la contrainte na&amp;icirc;tra l'id&amp;eacute;e. Je me suis rendu compte &lt;em&gt;a posteriori&lt;/em&gt; que nous avions fait le bon choix. Ou plut&amp;ocirc;t les bons choix, car en d&amp;eacute;cidant de prendre notre temps pour r&amp;eacute;fl&amp;eacute;chir, nous actions que la production, elle, aurait &amp;agrave; &amp;ecirc;tre rapide.&lt;/p&gt;
&lt;p&gt;Backup Train n'aurait pas vu le jour si nous n'avions d&amp;eacute;di&amp;eacute; que deux heures &amp;agrave; la r&amp;eacute;flexion. Le concept nous est, en effet, venu relativement tardivement. Or, il s'agit de la fondation du projet, sur laquelle il est difficile de revenir apr&amp;egrave;s coup. Autant donc partir confiant, ce que nous avons fait.&lt;/p&gt;
&lt;p&gt;Produire vite a aussi ses vertus. On se concentre sur l'essentiel, on touche plus rapidement au concret et, le diable &amp;eacute;tant dans les d&amp;eacute;tails, cela r&amp;eacute;v&amp;egrave;le des zones d'ombre qu'il &amp;eacute;tait impossible d'identifier lors de la r&amp;eacute;flexion initiale. Cela permet aussi de garder l'id&amp;eacute;e au chaud, que le d&amp;eacute;veloppement ne devienne pas une fin en soi. Le &lt;em&gt;in-browser prototyping &lt;/em&gt;s'inscrit parfaitement dans cette logique.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L'exp&amp;eacute;rience d'un concours est-elle transposable &amp;agrave; un cas r&amp;eacute;el&lt;/strong&gt;, en agence notamment ? Au moment d'&amp;eacute;tablir un r&amp;eacute;tro-planning, peut-on raisonnablement se dire : prenons tout le temps de la r&amp;eacute;flexion, on produira plus vite (et sans doute moins) ? Cela semble utopique, pourtant, l'id&amp;eacute;e est s&amp;eacute;duisante car elle&lt;strong&gt; impose des contraintes l&amp;agrave; o&amp;ugrave; elles sont b&amp;eacute;n&amp;eacute;fiques&lt;/strong&gt;. Sur la production, pour s&amp;eacute;parer l'essentiel du superflu, plut&amp;ocirc;t que sur la r&amp;eacute;flexion, o&amp;ugrave; le risque est d'aboutir &amp;agrave; une id&amp;eacute;e mort-n&amp;eacute;e.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Inter-disciplinarit&amp;eacute; obligatoire&lt;/h2&gt;
&lt;p&gt;Mon meilleur souvenir du challenge est le &lt;strong&gt;travail en commun et sans fronti&amp;egrave;res&lt;/strong&gt;. Bien entendu, nous avons tous nos sp&amp;eacute;cialit&amp;eacute;s, mais nous avons fourni un vrai travail d'&amp;eacute;quipe, d&amp;eacute;cloisonn&amp;eacute;. Habituellement, nous travaillons par phase : la conception, puis le graphisme, puis le d&amp;eacute;veloppement. Evidemment, les m&amp;eacute;thodes agiles permettent de casser ce cycle en V mais, cela n'emp&amp;ecirc;che, les phases de travail simultan&amp;eacute;es entre les diff&amp;eacute;rents corps de m&amp;eacute;tier ne sont pas si fr&amp;eacute;quentes que &amp;ccedil;a.&lt;/p&gt;
&lt;p&gt;Pour le WIF, nous avons tous suivi le projet de A &amp;agrave; Z. De l'id&amp;eacute;e &amp;agrave; la mise en ligne. On ne demandait pas l'avis d'un technicien pendant la phase de conception ou celui d'un graphiste lors de la finalisation. Il s'agissait de l'avis d'un &amp;eacute;quipier, peu importe sa sp&amp;eacute;cialit&amp;eacute; et peu importe la phase du projet.&lt;/p&gt;
&lt;p&gt;C'est le rush qui nous a impos&amp;eacute; cette inter-disciplinarit&amp;eacute; et c'est bien malheureux. Au quotidien, malgr&amp;eacute; toutes les vell&amp;eacute;it&amp;eacute;s d'agilit&amp;eacute; et de transversalit&amp;eacute;, &lt;strong&gt;nous cloisonnons, souvent inconsciemment&lt;/strong&gt;. Pourtant, rien de tel que de mettre la main &amp;agrave; la p&amp;acirc;te, au code pour un designer, au design pour un technicien, pour mieux comprendre l'autre et arriver, collectivement, &amp;agrave; une solution plus intelligente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Et maintenant ?&lt;/h2&gt;
&lt;p&gt;Les &lt;a href=&quot;http://webdesign-festival.com/2012/2012/03/les-creations-des-equipes-wif12/&quot; target=&quot;_blank&quot;&gt;r&amp;eacute;alisations des diff&amp;eacute;rentes &amp;eacute;quipes&lt;/a&gt; ont &amp;eacute;t&amp;eacute; publi&amp;eacute;es il y a peu. Je n'ai pas eu encore l'occasion de tout regarder (je doute l'avoir un jour), mais j'ai d&amp;eacute;j&amp;agrave; vu d'excellents projets. La partie s'annonce serr&amp;eacute;e.&lt;/p&gt;
&lt;p&gt;Les r&amp;eacute;sultats seront connus le 2 avril et je croise les doigts pour que la team Novius soit de la finale &amp;agrave; Limoges. L'occasion de renouveler cette exp&amp;eacute;rience de designer, au service de l'exp&amp;eacute;rience utilisateur.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Thu, 29 Mar 2012 17:00:00 +0200</pubDate>
   </item>
   <item>
       <title>Tutoriel FuelPHP #5 : la cheat sheet</title>
       <link>http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_41_vignette.png</img>
       <guid>http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_41_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Grâce aux &lt;a href=&quot;http://www.novius-labs.com/fuelphp,c,5.html&quot;&gt;quatre premiers volets&lt;/a&gt; de notre tutoriel FuelPHP, vous devriez maintenant être lancé(e) avec ce nouveau &lt;i&gt;framework&lt;/i&gt;. Maintenant, pour vous aider dans vos développements, nous avons réalisé une &lt;/i&gt;cheat sheet&lt;/i&gt;. Nous en avions nous-mêmes bien besoin pour le projet &lt;a href=&quot;http://www.novius-os.org&quot;&gt;Novius OS&lt;/a&gt;.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html&quot;&gt;Choix du framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot;&gt;Mise en place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot;&gt;Cr&amp;eacute;ation d'un projet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot;&gt;Application type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cheat sheet&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html&quot; target=&quot;_blank&quot;&gt;L'ORM : gestion des relations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.wijmo.com&quot; target=&quot;_blank&quot;&gt;Novius OS&lt;/a&gt; est un nouveau CMS open source motoris&amp;eacute; par FuelPHP (mais aussi par HTML5, &lt;a href=&quot;http://www.wijmo.com&quot; target=&quot;_blank&quot;&gt;Wijmo&lt;/a&gt; et d'autres). L'&amp;eacute;quipe de d&amp;eacute;veloppement utilise donc le &lt;em&gt;framework&lt;/em&gt; tous les jours ou presque. Difficile dans ces conditions de se passer d'une &lt;em&gt;cheat sheet&lt;/em&gt;. Malheureusement, aucune n'&amp;eacute;tait disponible... jusqu'&amp;agrave; aujourd'hui. Voici la premi&amp;egrave;re &lt;em&gt;cheat sheet&lt;/em&gt; FuelPHP par l'&amp;eacute;quipe de Novius OS :&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://nov.li/fuel&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/86.jpg&quot; alt=&quot;Cheat sheet FuelPHP par Novius OS&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;La &lt;em&gt;cheat sheet&lt;/em&gt; est disponible sous plusieurs formes : &lt;a href=&quot;http://nov.li/fuel&quot; target=&quot;_blank&quot;&gt;site web&lt;/a&gt;, mobile (scannez le QR code ci-dessus) et &lt;a href=&quot;http://www.novius-os.org/fuelphp-cheatsheet/fuelphp-cheatsheet-by-novius-os.pdf&quot; target=&quot;_blank&quot;&gt;PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A noter qu'elle est g&amp;eacute;n&amp;eacute;r&amp;eacute;e directement &amp;agrave; partir de la &lt;a href=&quot;http://docs.fuelphp.com/&quot; target=&quot;_blank&quot;&gt;documentation de FuelPHP&lt;/a&gt;. Le code de g&amp;eacute;n&amp;eacute;ration ainsi que l'UI sont disponibles sur un &lt;a href=&quot;https://github.com/novius-os/fuelphp-cheatsheet&quot; target=&quot;_blank&quot;&gt;d&amp;eacute;p&amp;ocirc;t GitHub d&amp;eacute;di&amp;eacute;&lt;/a&gt;. N'h&amp;eacute;sitez donc pas &amp;agrave; contribuer &amp;agrave; l'am&amp;eacute;lioration de cette &lt;em&gt;cheat sheet&lt;/em&gt;. En effet, elle a beau &amp;ecirc;tre belle, elle n'est pas parfaite pour autant ! Par exemple, seul le &lt;em&gt;core&lt;/em&gt; est document&amp;eacute;e, ajouter les packages serait une bonne id&amp;eacute;e.&lt;/p&gt;
&lt;p&gt;Bon(s) d&amp;eacute;veloppement(s) &amp;agrave; l'aide de la &lt;em&gt;cheat sheet&lt;/em&gt; et &amp;agrave; tr&amp;egrave;s vite pour d'autres tutoriaux FuelPHP.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Thu, 16 Feb 2012 17:03:00 +0100</pubDate>
   </item>
   <item>
       <title>Tutoriel FuelPHP #4 : une application type</title>
       <link>http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_38_vignette.png</img>
       <guid>http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_38_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Cet article s'inscrit dans la suite du précédent article &lt;a href=&quot;tutoriel-creation-projet-avec-fuelphp,35.html&quot;&gt;Création d'un projet avec FuelPHP&lt;/a&gt;. Le but de cet article n'est pas d'être complet, mais de vous donner les bases pour développer une application. L'exemple que nous allons étudier est un agenda.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Conception de l'agenda&lt;/h2&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html&quot;&gt;Choix du framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot;&gt;Mise en place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot;&gt;Cr&amp;eacute;ation d'un projet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Application type&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html&quot;&gt;Cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html&quot; target=&quot;_blank&quot;&gt;L'ORM : gestion des relations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;h3&gt;1. Structure des pages&lt;/h3&gt;
&lt;p&gt;Commen&amp;ccedil;ons par la structure des pages, tr&amp;egrave;s classique (voir r&amp;eacute;tro) pour ce type d&amp;rsquo;application.&lt;/p&gt;
&lt;p&gt;En partie sup&amp;eacute;rieure, le header, qui indique que nous nous trouvons dans l&amp;rsquo;agenda.&lt;br /&gt;Juste en dessous, un menu, nous indiquant dans quelle cat&amp;eacute;gorie nous nous trouvons.&lt;br /&gt;En dessous et &amp;agrave; gauche, la liste. Lorsqu&amp;rsquo;on se trouve dans la cat&amp;eacute;gorie Notes, il s&amp;rsquo;agit de la liste des notes. Quand on se trouve dans la cat&amp;eacute;gorie Adresses et num&amp;eacute;ros, il s&amp;rsquo;agit de la liste des adresses.&lt;br /&gt;&amp;Agrave; droite la vue : quand un utilisateur s&amp;eacute;lectionne un &amp;eacute;l&amp;eacute;ment dans la liste, il peut alors le visualiser et effectuer les actions de base dans cette partie.&lt;br /&gt;Tout en bas, le footer, reprenant le footer de FuelPHP.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/83.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Le header, le menu et le footer peuvent se pr&amp;eacute;senter directement dans le template.&lt;br /&gt;Par contre, la liste et la vue seront g&amp;eacute;n&amp;eacute;r&amp;eacute;es dans des vues diff&amp;eacute;rentes.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;2. Mod&amp;egrave;le de donn&amp;eacute;es&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot; target=&quot;_blank&quot;&gt;Nous avons d&amp;eacute;j&amp;agrave; cr&amp;eacute;&amp;eacute;&lt;/a&gt; les notes qui contiennent chacune un titre et une description.&lt;br /&gt;Nous rajouterons les personnes (cat&amp;eacute;gorie adresses et num&amp;eacute;ros), qui contiennent un nom, un pr&amp;eacute;nom, un num&amp;eacute;ro de t&amp;eacute;l&amp;eacute;phone, une adresse et des informations additionnelles.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Installation de fichiers annexes&lt;/h2&gt;
&lt;p&gt;Nous aurons besoin du framework jQuery, de fichiers CSS et d&amp;rsquo;images pour que le style soit d&amp;eacute;j&amp;agrave; en place. Ces ajouts cosm&amp;eacute;tiques (si on veut :)) ne sont pas l&amp;rsquo;objet de ce tutoriel (heureusement !). Vous pouvez trouver la source finale &lt;a href=&quot;https://github.com/sdrdis/Agenda&quot; target=&quot;_blank&quot;&gt;ici&lt;/a&gt;. Contentez vous de remplacer votre dossier public/assets par celui de la source finale.&lt;br /&gt;&lt;br /&gt;&amp;Agrave; noter que les fichiers CSS ont &amp;eacute;t&amp;eacute; g&amp;eacute;n&amp;eacute;r&amp;eacute;s avec le &lt;a href=&quot;http://compass-style.org/&quot; target=&quot;_blank&quot;&gt;framework Compass&lt;/a&gt;. Encore une fois, ce n'est pas l&amp;rsquo;objet de ce tutoriel.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Impl&amp;eacute;mentation&lt;/h2&gt;
&lt;h3&gt;1. Impl&amp;eacute;mentation du template&lt;/h3&gt;
&lt;p&gt;Avant de modifier les vues ou les actions, on va modifier le template qui repr&amp;eacute;sente la structure de la page.&lt;/p&gt;
&lt;p&gt;Ouvrez le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/template.php&lt;/strong&gt;&lt;/span&gt;, on y ins&amp;eacute;rera le code suivant :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code210&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;?php echo $title; ?&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;?php echo Asset::css('screen.css'); ?&amp;gt;
    &amp;lt;?php echo Asset::css('print.css'); ?&amp;gt;
    &amp;lt;!--[if IE]&amp;gt;
    &amp;lt;?php echo Asset::css('ie.css'); ?&amp;gt;
    &amp;lt;![endif]--&amp;gt;
    &amp;lt;?php echo Asset::css('agenda.css'); ?&amp;gt;
    &amp;lt;?php echo Asset::js('jquery-1.7.1.min.js'); ?&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div id=&amp;quot;main&amp;quot;&amp;gt;
    &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;
        Agenda
    &amp;lt;/div&amp;gt;
    &amp;lt;?php echo render('_menu'); ?&amp;gt;
    &amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;
        &amp;lt;?php if (Session::get_flash('error')): ?&amp;gt;
        &amp;lt;div class=&amp;quot;error&amp;quot;&amp;gt;&amp;lt;?php echo implode('&amp;lt;br/&amp;gt;', (array) Session::get_flash('error')); ?&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;?php endif; ?&amp;gt;
        &amp;lt;?php if (Session::get_flash('success')): ?&amp;gt;
        &amp;lt;div class=&amp;quot;success&amp;quot;&amp;gt;&amp;lt;?php echo implode('&amp;lt;br/&amp;gt;', (array) Session::get_flash('success')); ?&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;?php endif; ?&amp;gt;
            &amp;lt;div class=&amp;quot;inside&amp;quot;&amp;gt;
                &amp;lt;?php echo $content; ?&amp;gt;
            &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;
        &amp;lt;a href=&amp;quot;http://fuelphp.com&amp;quot;&amp;gt;Fuel&amp;lt;/a&amp;gt; is released under the MIT license.&amp;lt;br /&amp;gt;Page rendered in {exec_time}s using {mem_usage}mb of memory.
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On ajoute les fichiers CSS et JS via la classe &lt;span class=&quot;inline-code&quot;&gt;Asset&lt;/span&gt; (respectivement &lt;span class=&quot;inline-code&quot;&gt;Asset::css&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;Asset::js&lt;/span&gt;). Par exemple :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code212&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php echo Asset::css('screen.css'); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;g&amp;eacute;n&amp;eacute;rera le code suivant en HTML :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code211&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;http://localhost/mon_site_fuel/public/assets/css/screen.css?1322929428&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il s'agit encore d'helpers qui simplifient la t&amp;acirc;che de l'utilisateur. En plus de limiter le nombre de caract&amp;egrave;res &amp;agrave; &amp;eacute;crire, vous remarquerez, &amp;agrave; la fin de l'URL du fichier CSS, un nombre obligeant le navigateur &amp;agrave; recharger le fichier s'il a &amp;eacute;t&amp;eacute; modifi&amp;eacute; depuis la derni&amp;egrave;re visite (sans passer par le cache). Ces deux fonctions ont aussi d'autres param&amp;egrave;tres, je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/asset.html#/method_css&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sinon, vous pouvez facilement s&amp;eacute;parer les diff&amp;eacute;rentes parties qu'on avait d&amp;eacute;finies lors de l'introduction. Le header et le footer sont de simples DIV. Le menu est affich&amp;eacute; gr&amp;acirc;ce au partial &lt;span class=&quot;inline-code&quot;&gt;_menu&lt;/span&gt;. Dans le DIV &lt;span class=&quot;inline-code&quot;&gt;content&lt;/span&gt;, on constate que, pour le moment, aucune diff&amp;eacute;rentiation n'existe entre la zone &quot;Liste&quot; et la zone &quot;Vue&quot;. On y reviendra un peu plus tard dans cet article.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;2. Impl&amp;eacute;mentation du menu&lt;/h3&gt;
&lt;p&gt;Maintenant que nous faisons appel au partial &lt;span class=&quot;inline-code&quot;&gt;_menu&lt;/span&gt;, il faut bien impl&amp;eacute;menter le fichier. Cr&amp;eacute;ez le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/_menu.php&lt;/strong&gt;&lt;/span&gt; et ouvrez-le avec votre &amp;eacute;diteur pr&amp;eacute;f&amp;eacute;r&amp;eacute;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code213&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div id=&amp;quot;menu&amp;quot;&amp;gt;
    &amp;lt;?php echo Html::anchor('notes/index', 'Notes', array('class' =&amp;gt; 'item '.(\Request::active()-&amp;gt;controller == 'Controller_Notes' ? 'active' : ''))) ?&amp;gt;
    &amp;lt;?php echo Html::anchor('people/index', 'Adresses et numéros', array('class' =&amp;gt; 'item '.(\Request::active()-&amp;gt;controller == 'Controller_People' ? 'active' : ''))) ?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut voir qu'il s'agit avant tout d'un ensemble de liens. Vous connaissez d&amp;eacute;j&amp;agrave; la fonction &lt;span class=&quot;inline-code&quot;&gt;Html::anchor&lt;/span&gt; qui permet de g&amp;eacute;n&amp;eacute;rer des liens. On ajoute par d&amp;eacute;faut &amp;agrave; ces liens la classe &lt;span class=&quot;inline-code&quot;&gt;item&lt;/span&gt;, puis, conditionnellement, la classe &lt;span class=&quot;inline-code&quot;&gt;active&lt;/span&gt; permettant de surligner le menu actuel. Jetons un coup d'&amp;oelig;il &amp;agrave; la premi&amp;egrave;re condition :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code214&quot; class=&quot;cm-s-default&quot;&gt;\Request::active()-&amp;gt;controller == '\Controller_Notes' ? 'active' : ''&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;\Request::active()&lt;/span&gt; permet de r&amp;eacute;cup&amp;eacute;rer les information sur la requ&amp;ecirc;te de l'utilisateur. Notamment :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code215&quot; class=&quot;cm-s-default&quot;&gt;\Request::active()-&amp;gt;controller&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;qui permet de conna&amp;icirc;tre le contr&amp;ocirc;leur par lequel l'utilisateur est pass&amp;eacute;, et&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code216&quot; class=&quot;cm-s-default&quot;&gt;\Request::active()-&amp;gt;action&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;qui permet de conna&amp;icirc;tre l'action appel&amp;eacute;e. Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/request.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Conna&amp;icirc;tre le contr&amp;ocirc;leur et l'action qui ont &amp;eacute;t&amp;eacute; appel&amp;eacute;s peut &amp;ecirc;tre pratique dans certains cas dans les vues, mais c'est plus souvent le cas dans les contr&amp;ocirc;leurs. Dans le cas du menu, cela nous &amp;eacute;vite d'envoyer un param&amp;egrave;tre au niveau de chaque contr&amp;ocirc;leur pour indiquer le menu s&amp;eacute;lectionn&amp;eacute;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;3. G&amp;eacute;n&amp;eacute;ralisation du fonctionnement des contr&amp;ocirc;leurs&lt;span style=&quot;background-color: #ff0000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html&quot; target=&quot;_blank&quot;&gt;Dans l'article pr&amp;eacute;c&amp;eacute;dent&lt;/a&gt;, nous avons eu l'occasion de remarquer un certain nombre de r&amp;eacute;p&amp;eacute;titions dans les contr&amp;ocirc;leurs g&amp;eacute;n&amp;eacute;r&amp;eacute;s par Scaffold :&lt;/p&gt;
&lt;pre&gt;&lt;code id=&quot;code217&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Controller_Notes extends Controller_Template 
{

	public function action_index()
	{
		//...
		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Mes notes&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/index', $data);
	}

	public function action_view($id = null)
	{
		//...
		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Note&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/view', $data);
	}

	public function action_create($id = null)
	{
		//...
		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Notes&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/create');
	}

	public function action_edit($id = null)
	{
		//...
		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Notes&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/edit');
	}

	//...


}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ces r&amp;eacute;p&amp;eacute;tions peuvent sembler un peu excessives, notamment au niveau de l'attribut &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;content&lt;/span&gt;, o&amp;ugrave; l'on charge tout le temps le fichier vue. En effet, lorsqu'on appelle l'action &lt;span class=&quot;inline-code&quot;&gt;index&lt;/span&gt;, on affiche &lt;span class=&quot;inline-code&quot;&gt;notes/index&lt;/span&gt;, quand on appelle l'action &lt;span class=&quot;inline-code&quot;&gt;view&lt;/span&gt; on affiche &lt;span class=&quot;inline-code&quot;&gt;notes/view&lt;/span&gt; et, de mani&amp;egrave;re g&amp;eacute;n&amp;eacute;rale, lorsqu'on appelle l'action &lt;span class=&quot;inline-code&quot;&gt;NOM_ACTION&lt;/span&gt; du contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;NOM_CONTROLEUR&lt;/span&gt;, on s'attend &amp;agrave; afficher &lt;span class=&quot;inline-code&quot;&gt;NOM_CONTROLEUR/NOM_ACTION&lt;/span&gt; (c'est du moins le fonctionnement dans plusieurs frameworks, comme Rails ou Symfony).&lt;/p&gt;
&lt;p&gt;Il est, cependant, parfaitement possible de reproduire ces fonctionnements. Vu qu'on veut appliquer ces changements sur plusieurs contr&amp;ocirc;leurs, on peut cr&amp;eacute;er un nouveau contr&amp;ocirc;leur parent, qui sera &amp;eacute;tendu par les autres contr&amp;ocirc;leurs. Cr&amp;eacute;ons donc ce contr&amp;ocirc;leur &amp;agrave; l'adresse &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/controller/agenda.php&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&amp;Agrave; noter qu'il est possible de cr&amp;eacute;er ce contr&amp;ocirc;leur via &lt;span class=&quot;inline-code&quot;&gt;Oil&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code242&quot; class=&quot;cm-s-default&quot;&gt;oil generate controller agenda&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Mais, cette commande g&amp;eacute;n&amp;eacute;rera aussi des fichiers vues qui ne nous sont pas utiles (donc supprimez le dossier &lt;strong&gt;fuel/app/views/agenda/&lt;/strong&gt; si vous utilisez ce moyen). Pour atteindre le comportement cit&amp;eacute; plus haut, une impl&amp;eacute;mentation possible d'un tel fichier est :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code219&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Controller_Agenda extends Controller_Template{
    var $data = array(); // Données à envoyer dans la vue
    var $title = 'Agenda'; // Titre de la page. Défaut : Agenda
    var $view_dir; // Dossier vue du controlleur.

    public function after($response)
    {
        $action_name     = Request::active()-&amp;gt;action;
        $this-&amp;gt;template-&amp;gt;title   = $this-&amp;gt;title;
        $this-&amp;gt;template-&amp;gt;content = View::forge($this-&amp;gt;view_dir.'/'.$action_name, $this-&amp;gt;data);

        return parent::after($response);
    }
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot; target=&quot;_blank&quot;&gt;Lors d'un pr&amp;eacute;c&amp;eacute;dent article&lt;/a&gt;, nous avons expliqu&amp;eacute; l'ordre d'ex&amp;eacute;cution lorsqu'une requ&amp;ecirc;te est ex&amp;eacute;cut&amp;eacute;e. Tout ce qu'il faut comprendre ici, c'est que lorsqu'une requ&amp;ecirc;te est ex&amp;eacute;cut&amp;eacute;e :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;before&lt;/span&gt; est appel&amp;eacute;e&lt;/li&gt;
&lt;li&gt;Puis c'est la fonction correspondant &amp;agrave; l'action&lt;/li&gt;
&lt;li&gt;Puis la fonction &lt;span class=&quot;inline-code&quot;&gt;after&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Puis le template est affich&amp;eacute;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ainsi, la fonction &lt;span class=&quot;inline-code&quot;&gt;after&lt;/span&gt; sera toujours appel&amp;eacute;e apr&amp;egrave;s les actions des contr&amp;ocirc;leur &amp;eacute;tendant le contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;agenda&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Analysons le contenu de cette fonction :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tout d'abord, on r&amp;eacute;cup&amp;egrave;re le nom de l'action appel&amp;eacute;e via &lt;span class=&quot;inline-code&quot;&gt;Request::active()-&amp;gt;action&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;On remplit l'attribut &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;title&lt;/span&gt; avec &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;title&lt;/span&gt; qui, par d&amp;eacute;faut, vaut 'Agenda' (donc pas besoin de le d&amp;eacute;finir ; il y aura une valeur par d&amp;eacute;faut).&lt;/li&gt;
&lt;li&gt;On remplit enfin l'attribut &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;content&lt;/span&gt;, qui va afficher la vue issue du fichier &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;view_dir/fichier-au-nom-de-l-action-appelee&lt;/span&gt; (le dossier sera d&amp;eacute;fini dans le contr&amp;ocirc;leur). Les param&amp;egrave;tres du fichier vue proviennent de &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;data&lt;/span&gt;, d&amp;eacute;fini &amp;agrave; l'appel &amp;agrave; l'action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ainsi, le nouveau contr&amp;ocirc;leur Notes doit ressembler &amp;agrave; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code220&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Controller_Notes extends Controller_Agenda
{
    var $view_dir = 'notes';

	public function action_index()
	{
		$this-&amp;gt;data['notes'] = Model_Note::find_all();

	}

	public function action_view($id = null)
	{
		$this-&amp;gt;data['note'] = Model_Note::find_by_pk($id);

	}

	public function action_create($id = null)
	{
		if (Input::method() == 'POST')
		{
			$val = Model_Note::validate('create');
			
			if ($val-&amp;gt;run())
			{
				$note = Model_Note::forge(array(
					'titre' =&amp;gt; Input::post('titre'),
					'description' =&amp;gt; Input::post('description'),
				));

				if ($note and $note-&amp;gt;save())
				{
					Session::set_flash('success', 'Added note #'.$note-&amp;gt;id.'.');
					Response::redirect('notes');
				}
				else
				{
					Session::set_flash('error', 'Could not save note.');
				}
			}
			else
			{
				Session::set_flash('error', $val-&amp;gt;show_errors());
			}
		}

	}

	public function action_edit($id = null)
	{
		$note = Model_Note::find_one_by_id($id);

		if (Input::method() == 'POST')
		{
			$val = Model_Note::validate('edit');

			if ($val-&amp;gt;run())
			{
				$note-&amp;gt;titre = Input::post('titre');
				$note-&amp;gt;description = Input::post('description');

				if ($note-&amp;gt;save())
				{
					Session::set_flash('success', 'Updated note #'.$id);
					Response::redirect('notes');
				}
				else
				{
					Session::set_flash('error', 'Nothing updated.');
				}
			}
			else
			{
				Session::set_flash('error', $val-&amp;gt;show_errors());
			}
		}

		$this-&amp;gt;template-&amp;gt;set_global('note', $note, false);

	}

	public function action_delete($id = null)
	{
		if ($note = Model_Note::find_one_by_id($id))
		{
			$note-&amp;gt;delete();

			Session::set_flash('success', 'Deleted note #'.$id);
		}

		else
		{
			Session::set_flash('error', 'Could not delete note #'.$id);
		}

		Response::redirect('notes');

	}


}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Les actions sont ainsi un peu plus courtes (le contenu de &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt; ne fait qu'une seule ligne), on n'a plus besoin de sp&amp;eacute;cifier la vue &amp;agrave; afficher (&amp;ccedil;a nous permet aussi de forcer la norme &quot;une action / une vue d'un m&amp;ecirc;me nom&quot;), on ressemble plus aux frameworks existants et, enfin, on ne se pr&amp;eacute;occupe m&amp;ecirc;me plus du template.&lt;/p&gt;
&lt;p&gt;On est d'accord ; le fonctionnement pr&amp;eacute;c&amp;eacute;dent &amp;eacute;tait tout &amp;agrave; fait acceptable. Le but de cette impl&amp;eacute;mentation est avant tout de se simplifier la vie.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;4. Affichage vue et liste&lt;/h3&gt;
&lt;p&gt;Dans la partie pr&amp;eacute;c&amp;eacute;dente, on est parti de la supposition qu'&amp;agrave; chaque requ&amp;ecirc;te on n'affichait qu'une seule zone dans le template. Le cas de l'agenda est un peu plus sp&amp;eacute;cifique, on affiche deux zones : la zone liste et la zone vue.&lt;/p&gt;
&lt;p&gt;Tout d'abord, rempla&amp;ccedil;ons dans le template :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code222&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div class=&amp;quot;inside&amp;quot;&amp;gt;
     &amp;lt;?php echo $content; ?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;par&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code223&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div id=&amp;quot;list_zone&amp;quot;&amp;gt;
    &amp;lt;?php echo $list; ?&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;view_zone&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;inside&amp;quot;&amp;gt;
        &amp;lt;?php echo $view; ?&amp;gt;
   &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut maintenant afficher deux zones dans notre template &lt;span class=&quot;inline-code&quot;&gt;$list&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;$view&lt;/span&gt;. Il suffit de modifier le contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;agenda&lt;/span&gt; pour remplacer l'attribut &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;content&lt;/span&gt; par &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;view&lt;/span&gt;. On peut &amp;eacute;galement consid&amp;eacute;rer que &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;list&lt;/span&gt; affichera toujours la m&amp;ecirc;me vue liste. On remplace alors la fonction &lt;span class=&quot;inline-code&quot;&gt;after&lt;/span&gt; dans le contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;agenda&lt;/span&gt; par :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code224&quot; class=&quot;cm-s-default&quot;&gt;public function after($response)
{
    $action_name     = Request::active()-&amp;gt;action;
    $this-&amp;gt;template-&amp;gt;title   = $this-&amp;gt;title;
    $this-&amp;gt;template-&amp;gt;list = View::forge($this-&amp;gt;view_dir.'/list', $this-&amp;gt;data);
    $this-&amp;gt;template-&amp;gt;view = View::forge($this-&amp;gt;view_dir.'/'.$action_name, $this-&amp;gt;data);

    return parent::after($response);
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il faut cependant que la liste soit charg&amp;eacute;e. On peut le faire via la fonction &lt;span class=&quot;inline-code&quot;&gt;after&lt;/span&gt; du contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;Notes&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code225&quot; class=&quot;cm-s-default&quot;&gt;public function after($response)
{
    $this-&amp;gt;data['list'] = Model_Note::find(array('order_by' =&amp;gt; array('titre' =&amp;gt; 'asc')));

    return parent::after($response);
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il faut maintenant int&amp;eacute;grer la vue liste affichant l&amp;rsquo;ensemble des notes. Cr&amp;eacute;ez le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/list.php&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code226&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div class=&amp;quot;list notes_list&amp;quot;&amp;gt;
&amp;lt;?php if ($list): ?&amp;gt;
    &amp;lt;?php foreach ($list as $item): ?&amp;gt;
        &amp;lt;?php echo Html::anchor('notes/view/'.$item-&amp;gt;id, $item-&amp;gt;titre, array('class' =&amp;gt; (isset($note) &amp;amp;&amp;amp; $note-&amp;gt;id == $item-&amp;gt;id) ? 'active' : '')); ?&amp;gt;
    &amp;lt;?php endforeach; ?&amp;gt;
&amp;lt;?php else: ?&amp;gt;
&amp;lt;div&amp;gt;Pas de notes pour le moment&amp;lt;/div&amp;gt;
&amp;lt;?php endif; ?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Le script ressemble un peu au script &lt;span class=&quot;inline-code&quot;&gt;index.php&lt;/span&gt; actuel. Il liste les notes, et si une note est s&amp;eacute;lectionn&amp;eacute;e (si &lt;span class=&quot;inline-code&quot;&gt;$note&lt;/span&gt; est d&amp;eacute;finie), il la surligne.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;5. Vues CRUD&lt;/h3&gt;
&lt;p&gt;Quelques modifications doivent &amp;ecirc;tre apport&amp;eacute;es aux fichiers vues pr&amp;eacute;c&amp;eacute;demment g&amp;eacute;n&amp;eacute;r&amp;eacute;s par Scaffold.&lt;br /&gt;&lt;br /&gt;La vue index est affich&amp;eacute;e quand aucune note n&amp;rsquo;est s&amp;eacute;lectionn&amp;eacute;e. Il faut modifier son contenu en cons&amp;eacute;quence :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code227&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div class=&amp;quot;no_content&amp;quot;&amp;gt;
    Vous pouvez sélectionner une note&amp;lt;br/&amp;gt;
    ou &amp;lt;a href=&amp;quot;&amp;lt;?php echo Uri::create('notes/create/') ?&amp;gt;&amp;quot;&amp;gt;en créer une&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lorsque l&amp;rsquo;on visualise une note, on aimerait, au lieu de devoir cliquer sur des liens, pouvoir effectuer des actions via un ensemble de boutons :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/84.png&quot; alt=&quot;&quot; width=&quot;300&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;Eacute;tant donn&amp;eacute; qu&amp;rsquo;on veut pouvoir r&amp;eacute;utiliser ces boutons, il convient de cr&amp;eacute;er un partial. Nous pouvons cr&amp;eacute;er le partial &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/_action_buttons.php&lt;/strong&gt;&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code228&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
    $menus = array(
        'edit'        =&amp;gt; 'Modifier',
        'delete'    =&amp;gt; 'Supprimer',
        'cancel'    =&amp;gt; 'Annuler',
        'save'        =&amp;gt; 'Sauvegarder',
        'add'        =&amp;gt; 'Nouveau',
    );
?&amp;gt;
&amp;lt;div class=&amp;quot;context_menu&amp;quot;&amp;gt;
    &amp;lt;?php foreach ($menu as $item =&amp;gt; $attr) {
        if (!is_array($attr)) {
            $attr = array('href' =&amp;gt; $attr);
        }
        $attr['class'] = $item;
?&amp;gt;
        &amp;lt;a &amp;lt;?php echo array_to_attr($attr) ?&amp;gt; &amp;gt;&amp;lt;?php echo $menus[$item] ?&amp;gt;&amp;lt;/a&amp;gt;
    &amp;lt;?php } ?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;Agrave; noter que ce partial utilise la fonction &lt;span class=&quot;inline-code&quot;&gt;array_to_attr&lt;/span&gt;, qui transforme un tableau en attributs pour les &amp;eacute;l&amp;eacute;ment du DOM. Je vous invite &amp;agrave; aller voir la &lt;a href=&quot;http://docs.fuelphp.com/classes/html.html#/function_array_to_attr&quot; target=&quot;_blank&quot;&gt;documentation associ&amp;eacute;e&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Les modifications suivantes tirent parti du partial &lt;span class=&quot;inline-code&quot;&gt;_action_button&lt;/span&gt; et modifient l&amp;eacute;g&amp;egrave;rement le code pour des raisons cosm&amp;eacute;tiques.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/_form.php&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre&gt;&lt;code id=&quot;code229&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php echo Form::open(); ?&amp;gt;
    &amp;lt;p&amp;gt;
        &amp;lt;?php echo Form::label('Titre', 'titre'); ?&amp;gt;
&amp;lt;?php echo Form::input('titre', Input::post('titre', isset($note) ? $note-&amp;gt;titre : '')); ?&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;
        &amp;lt;?php echo Form::label('Description', 'description'); ?&amp;gt;
&amp;lt;?php echo Form::textarea('description', Input::post('description', isset($note) ? $note-&amp;gt;description : '')); ?&amp;gt;
    &amp;lt;/p&amp;gt;
&amp;lt;?php echo Form::close(); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/create.php&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre&gt;&lt;code id=&quot;code231&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
echo render('_action_buttons', array(
            'menu' =&amp;gt; array(
                'save' =&amp;gt; array('href' =&amp;gt; '#', 'onclick' =&amp;gt; &amp;quot;$(this).closest('#view_zone').find('form').submit(); return false;&amp;quot;),
                'cancel' =&amp;gt; Uri::create('notes/index'),
            )
        )
    );
?&amp;gt;
&amp;lt;?php echo render('notes/_form'); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/edit.php&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre&gt;&lt;code id=&quot;code232&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
echo render('_action_buttons', array(
            'menu' =&amp;gt; array(
                'save' =&amp;gt; array('href' =&amp;gt; '#', 'onclick' =&amp;gt; &amp;quot;$(this).closest('#view_zone').find('form').submit(); return false;&amp;quot;),
                'cancel' =&amp;gt; Uri::create('notes/view/'.$note-&amp;gt;id),
            )
        )
    );
?&amp;gt;
&amp;lt;?php echo render('notes/_form'); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/view.php&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code233&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
    echo render('_action_buttons', array(
            'menu' =&amp;gt; array(
                'add' =&amp;gt; Uri::create('notes/create'),
                'edit' =&amp;gt; Uri::create('notes/edit/'.$note-&amp;gt;id),
                'delete' =&amp;gt; Uri::create('notes/delete/'.$note-&amp;gt;id),
            )
        )
    );
?&amp;gt;
&amp;lt;label&amp;gt;Titre&amp;lt;/label&amp;gt;
    &amp;lt;?php echo $note-&amp;gt;titre; ?&amp;gt;
&amp;lt;label&amp;gt;Description&amp;lt;/label&amp;gt;
    &amp;lt;?php echo nl2br($note-&amp;gt;description); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;6. Support de la cat&amp;eacute;gorie &amp;ldquo;Adresses et num&amp;eacute;ros&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;On peut d&amp;eacute;sormais ajouter le support pour la cat&amp;eacute;gorie &amp;ldquo;Adresses et num&amp;eacute;ros&amp;rdquo;. Cette cat&amp;eacute;gorie affiche, en fait, une liste de personnes. Nous appellerons donc son contr&amp;ocirc;leur People.&lt;br /&gt;On g&amp;eacute;n&amp;egrave;re d&amp;rsquo;abord le code par Scaffold :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code243&quot; class=&quot;cm-s-default&quot;&gt;php oil generate scaffold/crud person name:string surname:string tel:string email:string address:text additionals:text&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/85.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;Eacute;l&amp;eacute;ment int&amp;eacute;ressant dans la g&amp;eacute;n&amp;eacute;ration, la gestion du singulier / pluriel. On a appel&amp;eacute; un scaffold bas&amp;eacute; sur le nouvel objet &lt;span class=&quot;inline-code&quot;&gt;Person&lt;/span&gt;, mais Oil a g&amp;eacute;n&amp;eacute;r&amp;eacute; un mod&amp;egrave;le &lt;span class=&quot;inline-code&quot;&gt;person.php&lt;/span&gt; ainsi qu'un fichier migration 002_create_people.php. C&amp;rsquo;est un choix que fait aussi Rails. Attention cependant, le singulier / pluriel n&amp;rsquo;est probablement bien g&amp;eacute;r&amp;eacute; qu&amp;rsquo;en anglais.&lt;br /&gt;&lt;br /&gt;La liste des fichiers g&amp;eacute;n&amp;eacute;r&amp;eacute;s est presque similaire, seul le template n&amp;rsquo;a pas &amp;eacute;t&amp;eacute; g&amp;eacute;n&amp;eacute;r&amp;eacute; car il est d&amp;eacute;j&amp;agrave; pr&amp;eacute;sent.&lt;br /&gt;&lt;br /&gt;Il faut maintenant lancer la migration :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code244&quot; class=&quot;cm-s-default&quot;&gt;php oil refine migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Pour l&amp;rsquo;impl&amp;eacute;mentation des vues et du contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;People&lt;/span&gt;, vous pouvez copier les fichiers &amp;agrave; partir du dossier source. Sinon, &amp;ccedil;a peut &amp;ecirc;tre une bon exercice d&amp;rsquo;adapter les fichiers g&amp;eacute;n&amp;eacute;r&amp;eacute;s &amp;agrave; partir du scaffold.&lt;/p&gt;
&lt;p&gt;Juste un remarque : rendez-vous dans le fichier mod&amp;egrave;le g&amp;eacute;n&amp;eacute;r&amp;eacute; &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/model/person.php&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code236&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Model_Person extends Model_Crud
{
	protected static $_table_name = 'people';
	
	public static function validate($factory)
	{
		$val = Validation::forge($factory);
		$val-&amp;gt;add_field('name', 'Name', 'required|max_length[255]');
		$val-&amp;gt;add_field('surname', 'Surname', 'required|max_length[255]');
		$val-&amp;gt;add_field('tel', 'Tel', 'required|max_length[255]');
		$val-&amp;gt;add_field('email', 'Email', 'required|valid_email|max_length[255]');
		$val-&amp;gt;add_field('address', 'Address', 'required');
		$val-&amp;gt;add_field('additionals', 'Additionals', 'required');

		return $val;
	}

}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Si on analyse la fonction &lt;span class=&quot;inline-code&quot;&gt;validate&lt;/span&gt;, tous les champs &lt;span class=&quot;inline-code&quot;&gt;string&lt;/span&gt; ont le validateur &lt;span class=&quot;inline-code&quot;&gt;required|max_length[255]&lt;/span&gt; et tous les champs &lt;span class=&quot;inline-code&quot;&gt;text&lt;/span&gt; ont le validateur &lt;span class=&quot;inline-code&quot;&gt;required&lt;/span&gt; (hormis email qui a le validateur &lt;span class=&quot;inline-code&quot;&gt;required|valid_email|max_length[255]&lt;/span&gt;, qui teste s'il s'agit d'un email valide). Lorsqu'un champ s'appelle &lt;span class=&quot;inline-code&quot;&gt;email&lt;/span&gt;, Oil ajoute automatiquement ce validateur. Il s'agit d'une valeur sp&amp;eacute;ciale (apparemment la seule, pour le moment), donc sachez que le choix du nom du champ peut aussi avoir un impact sur le code g&amp;eacute;n&amp;eacute;r&amp;eacute; par Scaffold.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;7. Renommer la colonne titre&lt;/h3&gt;
&lt;p&gt;Les plus attentifs d'entre vous ont d&amp;ucirc; remarquer qu'on est pass&amp;eacute; &amp;agrave; une notation en anglais. Pourtant, dans le mod&amp;egrave;le &lt;span class=&quot;inline-code&quot;&gt;note&lt;/span&gt;, on a une colonne &lt;span class=&quot;inline-code&quot;&gt;titre&lt;/span&gt; en fran&amp;ccedil;ais. Nous allons renommer cette colonne par le syst&amp;egrave;me de migration.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code245&quot; class=&quot;cm-s-default&quot;&gt;php oil generate migration rename_field_titre_to_title_in_notes&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Jetons un coup d'&amp;oelig;il au fichier g&amp;eacute;n&amp;eacute;r&amp;eacute; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code238&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php

namespace Fuel\Migrations;

class Rename_field_titre_to_title_in_notes
{
	public function up()
	{
		\DBUtil::modify_fields('notes', array(
			'titre' =&amp;gt; array('name' =&amp;gt; 'title', 'type' =&amp;gt; 'varchar', 'constraint' =&amp;gt; 255)
		));
	}

	public function down()
	{
    \DBUtil::modify_fields('notes', array(
			'title' =&amp;gt; array('name' =&amp;gt; 'titre', 'type' =&amp;gt; 'varchar', 'constraint' =&amp;gt; 255)
		));
	}
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Le g&amp;eacute;n&amp;eacute;rateur nous a g&amp;eacute;n&amp;eacute;r&amp;eacute; une classe avec deux fonctions : la fonction &lt;span class=&quot;inline-code&quot;&gt;up&lt;/span&gt; et la fonction &lt;span class=&quot;inline-code&quot;&gt;down&lt;/span&gt;. Ces deux fonctions permettent d'effectuer les migrations. &lt;span class=&quot;inline-code&quot;&gt;Up &lt;/span&gt;est appel&amp;eacute;e lorsqu'on veut effectuer la migration, &lt;span class=&quot;inline-code&quot;&gt;down&lt;/span&gt; quand on souhaite l'annuler.&lt;/p&gt;
&lt;p&gt;Nous avons fait appel &amp;agrave; une migration magique, si bien que ces fonctions sont pr&amp;eacute;-remplies. Si on avait g&amp;eacute;n&amp;eacute;r&amp;eacute; la migration avec un nom diff&amp;eacute;rent, les fonctions auraient probablement &amp;eacute;t&amp;eacute; vides. Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/packages/oil/generate.html#/magic_migrations&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;\DBUtil::modify_fields&lt;/span&gt; semble souffrir, pour l'instant, d'un l&amp;eacute;ger dysfonctionnement. Je vous conseille donc de remplacer les fonctions &lt;span class=&quot;inline-code&quot;&gt;up&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;down&lt;/span&gt;. C'est l'occasion de comprendre les requ&amp;ecirc;tes sens&amp;eacute;es &amp;ecirc;tre ex&amp;eacute;cut&amp;eacute;es.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code239&quot; class=&quot;cm-s-default&quot;&gt;public function up()
{
        \DB::query('ALTER TABLE `notes` CHANGE `titre` `title` VARCHAR( 255 )')-&amp;gt;execute();
}

public function down()
{
        \DB::query('ALTER TABLE `notes` CHANGE `title` `titre` VARCHAR( 255 )')-&amp;gt;execute();
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lorsqu'on ex&amp;eacute;cute :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code246&quot; class=&quot;cm-s-default&quot;&gt;php oil refine migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;C'est la fonction &lt;span class=&quot;inline-code&quot;&gt;up &lt;/span&gt;qui est appel&amp;eacute;e. La colonne titre est alors renomm&amp;eacute;e en title. Si on veut revenir en arri&amp;egrave;re (&amp;agrave; cause, mettons, d'une fausse manipulation), on peut ex&amp;eacute;cuter :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code247&quot; class=&quot;cm-s-default&quot;&gt;php oil refine migrate:down&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;C'est la fonction &lt;span class=&quot;inline-code&quot;&gt;down&lt;/span&gt; qui est alors ex&amp;eacute;cut&amp;eacute;e.&lt;/p&gt;
&lt;p&gt;Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/general/migrations.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Une fois la migration effectu&amp;eacute;e, n'oubliez pas d'aller modifier le code.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Pistes d'am&amp;eacute;liorations&lt;/h2&gt;
&lt;p&gt;L'agenda que nous avons d&amp;eacute;velopp&amp;eacute; est loin d'&amp;ecirc;tre termin&amp;eacute;. Voici quelques am&amp;eacute;liorations possibles. Certains de ces points feront l'objet de tutoriels prochainement.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il serait parfaitement possible de rajouter un syst&amp;egrave;me d'authentification. On pourrait, par exemple, cr&amp;eacute;er une table &lt;span class=&quot;inline-code&quot;&gt;user&lt;/span&gt;, puis rajouter des colonnes &lt;span class=&quot;inline-code&quot;&gt;user_id&lt;/span&gt; dans les tables &lt;span class=&quot;inline-code&quot;&gt;notes&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;person&lt;/span&gt;. On utiliserait la classe &lt;span class=&quot;inline-code&quot;&gt;Session&lt;/span&gt;. Vous pouvez consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/session/config.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Pour le mod&amp;egrave;le &lt;span class=&quot;inline-code&quot;&gt;Person&lt;/span&gt;, les champs ne sont-ils peut-&amp;ecirc;tre pas tous obligatoires par d&amp;eacute;faut ? Peut-&amp;ecirc;tre faut-il rajouter des conditions de validation suppl&amp;eacute;mentaires ? Vous pouvez aussi consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/validation/validation.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;La page d'accueil demande aussi &amp;agrave; &amp;ecirc;tre chang&amp;eacute;e (elle est toujours sur welcome). Si on veut que la page d'accueil pointe vers les notes, on peut modifier le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/config/routes.php&lt;/strong&gt;&lt;/span&gt; et remplacer : &lt;span class=&quot;inline-code&quot;&gt;'_root_' =&amp;gt; 'welcome/index'&lt;/span&gt; par &lt;span class=&quot;inline-code&quot;&gt;'_root_' =&amp;gt; 'notes/index'&lt;/span&gt;. Les possibilit&amp;eacute; des routes sont multiples, je vous conseille de consulter &lt;a href=&quot;http://docs.fuelphp.com/general/routing.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;</description>
       <dc:creator>Sébastien Drouyer </dc:creator>
       <pubDate>Mon, 09 Jan 2012 17:54:00 +0100</pubDate>
   </item>
   <item>
       <title>jQuery UI Button : buttonset de radio/checkbox avec seulement des icônes</title>
       <link>http://www.novius-labs.com/jquery-button-buttonset-radio-checkbox-avec-seulement-icones,39.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_39_vignette.png</img>
       <guid>http://www.novius-labs.com/jquery-button-buttonset-radio-checkbox-avec-seulement-icones,39.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_39_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Voici un petit billet pour faire profiter d'une astuce pour le widget jQuery UI Button : créer un &lt;i&gt;buttonset&lt;/i&gt; (regroupement de boutons comme sur l'image illustrant ce billet) basé sur des inputs &lt;i&gt;radio&lt;/i&gt; (ou &lt;i&gt;checkbox&lt;/i&gt;)&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;Si vous lisez attentivement la documentation et les exemples du widget &lt;strong&gt;Button&lt;/strong&gt; de &lt;strong&gt;jQuery UI&lt;/strong&gt;, vous saurez tr&amp;egrave;s facilement cr&amp;eacute;er un &lt;em&gt;&lt;strong&gt;buttonset&lt;/strong&gt;&lt;/em&gt; &amp;agrave; partir d'une liste d'&lt;a href=&quot;http://jqueryui.com/demos/button/#radio&quot; target=&quot;_blank&quot;&gt;inputs &lt;em&gt;radio&lt;/em&gt;&lt;/a&gt; ou &lt;em&gt;&lt;a href=&quot;http://jqueryui.com/demos/button/#checkbox&quot; target=&quot;_blank&quot;&gt;checkbox&lt;/a&gt;&lt;/em&gt;. Techniquement, le widget r&amp;eacute;cup&amp;egrave;re les LABEL associ&amp;eacute;s aux INPUT pour cr&amp;eacute;er les BUTTONS. L'avantage de passer par des &lt;em&gt;radio&lt;/em&gt; ou des &lt;em&gt;checkbox&lt;/em&gt; est que le widget g&amp;egrave;re l'&amp;eacute;tat on / off du boutton en fonction de l'attribut &lt;em&gt;checked&lt;/em&gt; de l'INPUT.&lt;/p&gt;
&lt;p&gt;Dans un &lt;a href=&quot;http://jqueryui.com/demos/button/#icons&quot; target=&quot;_blank&quot;&gt;autre exemple&lt;/a&gt;, vous apprenez &amp;agrave; cr&amp;eacute;er des bouttons avec un ou deux ic&amp;ocirc;nes, avec ou sans texte.&lt;/p&gt;
&lt;p&gt;Oui, mais vous ce que vous voulez, c'est un groupe de boutons bas&amp;eacute;s sur des &lt;em&gt;radio&lt;/em&gt; ou des &lt;em&gt;checkbox&lt;/em&gt; ET repr&amp;eacute;sent&amp;eacute;s seulement par des ic&amp;ocirc;nes. Et l&amp;agrave;, pas d'exemple disponible.&lt;/p&gt;
&lt;p&gt;J'ai d'abord essay&amp;eacute; de mettre les ic&amp;ocirc;nes directement dans les LABEL, via un tag IMG ou via un SPAN avec la classe CSS &lt;span class=&quot;inline-code&quot;&gt;ui-icon&lt;/span&gt;. Mais, le r&amp;eacute;sultat n'&amp;eacute;tait pas convainquant : les boutons &amp;eacute;taient plus gros qu'&amp;agrave; la normale.&lt;/p&gt;
&lt;p&gt;J'ai essay&amp;eacute; de simuler l'effet &lt;em&gt;radio&lt;/em&gt; (ou &lt;em&gt;checkbox&lt;/em&gt;) avec un boutton classique et en for&amp;ccedil;ant la classe CSS &lt;span class=&quot;inline-code&quot;&gt;ui-state-active&lt;/span&gt; sur le bouton actif. Mais, le widget, dans les cas non &lt;em&gt;radio&lt;/em&gt; ou &lt;em&gt;checkbox&lt;/em&gt;, enl&amp;egrave;ve la classe &lt;span class=&quot;inline-code&quot;&gt;ui-state-active&lt;/span&gt; sur le &lt;span class=&quot;inline-code&quot;&gt;mouseout&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;J'ai donc mis le nez dans le code du widget pour voir comment il marchait. C'est du bel ouvrage !! Dans la partie sp&amp;eacute;cifique aux &lt;em&gt;buttonset&lt;/em&gt;, j'ai remarqu&amp;eacute; que le widget cherchait tous les &lt;span class=&quot;inline-code&quot;&gt;:button, :submit, :reset, :checkbox, :radio, a, :data(button)&lt;/span&gt; contenus dans l'&amp;eacute;l&amp;eacute;ment englobant. Ensuite, pour chacun, il v&amp;eacute;rifiait s'il avait d&amp;eacute;j&amp;agrave; &amp;eacute;t&amp;eacute; transform&amp;eacute; en &lt;span class=&quot;inline-code&quot;&gt;ui-button&lt;/span&gt;. Si oui, il le rafraichissait, si non, il l'initialisait. &lt;strong&gt;BINGO&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;La voil&amp;agrave; ma solution : d'abord initialiser un &amp;agrave; un mes inputs &lt;em&gt;radio&lt;/em&gt; en passant les bons param&amp;egrave;tres et seulement ensuite initialiser le &lt;em&gt;buttonset&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code249&quot; class=&quot;cm-s-default&quot;&gt;//En partant du principe que le suffixe de l'icône à afficher est contenu dans la valeur de chaque radio

// On cherche tous les radio contenu dans un élément servant de container au groupement de boutons
$('#buttonset').find(':radio')

// Boucle sur les radios
.each(function() {
    var input = $(this);
    // Initialisation du bouton : 1 icône mais le label non affiché
    input.button({
        text : false,
        icons : {
             primary: 'ui-icon ui-icon-' + input.val()
        }
    });
})

// On revient au groupement de boutons et on l'initialise
.end()
.buttonset();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Et le r&amp;eacute;sultat (vous pouvez faire joujou avec sur JSBin).&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;http://jsbin.com/ivopuh/8&quot; style=&quot;width:100%;height:100px;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Vous pourrez &amp;eacute;galement voir le r&amp;eacute;sultat en live d'ici quelques jours / heures dans la &lt;a href=&quot;http://www.novius-os.org/demo.html&quot; target=&quot;_blank&quot;&gt;d&amp;eacute;mo de Novius OS&lt;/a&gt;, application M&amp;eacute;diath&amp;egrave;que.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Mon, 09 Jan 2012 17:46:00 +0100</pubDate>
   </item>
   <item>
       <title>Tutoriel : Création d'un projet avec FuelPHP</title>
       <link>http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_35_vignette.png</img>
       <guid>http://www.novius-labs.com/tutoriel-creation-projet-avec-fuelphp,35.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_35_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;La semaine dernière, j’ai rejoint l’équipe du projet open-source &lt;a href=&quot;http://www.novius-os.org&quot;&gt;Novius OS&lt;/a&gt; basé sur le framework FuelPHP. Mes collègues de Novius Labs m’ont initié à ce nouveau framework. Je prends donc la suite de Julian pour vous en expliquer le fonctionnement. Aujourd’hui, on rentre dans le détail et passons à un cas concret.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #990000;&quot;&gt;&lt;strong&gt;Note du 20/12/2011 : &lt;/strong&gt;cet article a &amp;eacute;t&amp;eacute; mis &amp;agrave; jour par rapport &amp;agrave; la nouvelle version 1.1 de Fuel &lt;/span&gt;&lt;a href=&quot;http://fuelphp.com/blog/2011/12/version-1-1-finally-lands&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;color: #990000;&quot;&gt;sortie r&amp;eacute;cemment&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #990000;&quot;&gt;. Les codes affich&amp;eacute;s, les commandes ainsi que certaines prises d'&amp;eacute;cran ont donc sensiblement chang&amp;eacute;s depuis la version initiale.&lt;/span&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Objectif&lt;/h2&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html&quot;&gt;Choix du framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot;&gt;Mise en place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cr&amp;eacute;ation d'un projet&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot;&gt;Application type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html&quot;&gt;Cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html&quot; target=&quot;_blank&quot;&gt;L'ORM : gestion des relations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;L&amp;rsquo;objectif de cet article n&amp;rsquo;est pas d&amp;rsquo;&amp;ecirc;tre exhaustif sur le framework, mais de vous donner les armes n&amp;eacute;cessaires pour commencer un projet. La connaissance d&amp;rsquo;un framework PHP ou autre (Ruby on Rails, Symfony, CakePHP...) est un plus mais n&amp;rsquo;est pas n&amp;eacute;cessaire pour suivre ce tutoriel.&lt;/p&gt;
&lt;p&gt;Tout au long des articles 3 et 4 de notre tutoriel FuelPHP, nous allons nous baser sur un exemple : l&amp;rsquo;&amp;eacute;laboration d&amp;rsquo;un agenda accessible via internet (o&amp;ugrave; il est possible d&amp;rsquo;&amp;eacute;crire des notes, d&amp;rsquo;entrer ses contacts etc...).&lt;/p&gt;
&lt;p&gt;Pour les curieux, voici un aper&amp;ccedil;u :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/63.png&quot; alt=&quot;&quot; width=&quot;400&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Vous vous en doutez, la r&amp;eacute;alisation graphique ne fait pas partie des objectifs de ce tutoriel. Je tiens n&amp;eacute;anmoins &amp;agrave; donner le cr&amp;eacute;dit des ic&amp;ocirc;nes issues de l&amp;rsquo;excellent site &lt;a href=&quot;http://thenounproject.com/&quot; target=&quot;_blank&quot;&gt;the Noun Project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce tutoriel part du principe que vous avez lu &lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot; target=&quot;_blank&quot;&gt;l&amp;rsquo;article pr&amp;eacute;c&amp;eacute;dent de Julian&lt;/a&gt; et install&amp;eacute; une instance du projet. Nous utiliserons MySQL et un logiciel de gestion de base de donn&amp;eacute;es (phpMyAdmin).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Configuration de la base de donn&amp;eacute;es&lt;/h2&gt;
&lt;p&gt;Via votre logiciel de gestion de base de donn&amp;eacute;es pr&amp;eacute;f&amp;eacute;r&amp;eacute;, cr&amp;eacute;ez une base de donn&amp;eacute;es que vous nommerez &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;tuto_agenda&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Il faut maintenant configurer FuelPHP pour qu&amp;rsquo;il puisse acc&amp;eacute;der &amp;agrave; cette base.&lt;/p&gt;
&lt;p&gt;Il faut d&amp;rsquo;abord modifier le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/config/db.php&lt;/strong&gt;&lt;/span&gt; qui va vous permettre d&amp;rsquo;acc&amp;eacute;der &amp;agrave; votre serveur MySQL. Voici ce que contient le fichier de base :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code190&quot; class=&quot;cm-s-default&quot;&gt;return array(
	'active' =&amp;gt; 'default',

	/**
	 * Base config, just need to set the DSN, username and password in env. config.
	 */
	'default' =&amp;gt; array(
		'type'        =&amp;gt; 'pdo',
		'connection'  =&amp;gt; array(
			'persistent' =&amp;gt; false,
		),
		'identifier'   =&amp;gt; '`',
		'table_prefix' =&amp;gt; '',
		'charset'      =&amp;gt; 'utf8',
		'caching'      =&amp;gt; false,
		'profiling'    =&amp;gt; false,
	),

	'redis' =&amp;gt; array(
		'default' =&amp;gt; array(
			'hostname'  =&amp;gt; '127.0.0.1',
			'port'      =&amp;gt; 6379,
		)
	),

);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut voir qu&amp;rsquo;on peut ici sp&amp;eacute;cifier les informations de connexion (le type, l&amp;rsquo;adresse et le port du serveur - &lt;span class=&quot;inline-code&quot;&gt;type&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;hostname&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;port&lt;/span&gt;) ainsi que certaines options (gestion du cache, le pr&amp;eacute;fixe &amp;agrave; utiliser devant chaque table...).&lt;/p&gt;
&lt;p&gt;Le type de base est PDO. Il est possible de le laisser tel quel, cependant certaines op&amp;eacute;rations de migration de ce type ne sont pas encore support&amp;eacute;es par FuelPHP. Nous allons donc modifier ce type en MySQL. Nous ne modifierons aucun des autres param&amp;egrave;tres, ce n&amp;rsquo;est pas l&amp;rsquo;objet de ce tutoriel.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code191&quot; class=&quot;cm-s-default&quot;&gt;return array(
	'active' =&amp;gt; 'default',

	/**
	 * Base config, just need to set the DSN, username and password in env. config.
	 */
	'default' =&amp;gt; array(
		'type'        =&amp;gt; 'mysql',
		'connection'  =&amp;gt; array(
			'persistent' =&amp;gt; false,
		),
		'identifier'   =&amp;gt; '`',
		'table_prefix' =&amp;gt; '',
		'charset'      =&amp;gt; 'utf8',
		'caching'      =&amp;gt; false,
		'profiling'    =&amp;gt; false,
	),

	'redis' =&amp;gt; array(
		'default' =&amp;gt; array(
			'hostname'  =&amp;gt; '127.0.0.1',
			'port'      =&amp;gt; 6379,
		)
	),

);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il faut maintenant sp&amp;eacute;cifier les identifiants et la base sur laquelle se connecter. Le framework FuelPHP propose, par d&amp;eacute;faut, de s&amp;eacute;parer cette partie de la configuration entre mode de d&amp;eacute;veloppement et mode de production. Nous allons suivre cette d&amp;eacute;marche, mais sachez qu&amp;rsquo;il est possible de tout configurer dans le fichier pr&amp;eacute;c&amp;eacute;dent. A l'inverse, il est possible de sp&amp;eacute;cifier des bases de donn&amp;eacute;es diff&amp;eacute;rentes et d&amp;rsquo;autres configurations dans les fichiers de configuration d&amp;eacute;veloppement / production.&lt;/p&gt;
&lt;p&gt;Si la configuration n&amp;rsquo;a pas &amp;eacute;t&amp;eacute; modifi&amp;eacute;e, nous sommes normalement en mode d&amp;eacute;veloppement. Ouvrez donc le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/config/development/db.php&lt;/strong&gt;&lt;/span&gt;. Le contenu de base est le suivant :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code192&quot; class=&quot;cm-s-default&quot;&gt;return array(
	'default' =&amp;gt; array(
		'connection'  =&amp;gt; array(
			'dsn'        =&amp;gt; 'mysql:host=localhost;dbname=fuel_dev',
			'username'   =&amp;gt; 'root',
			'password'   =&amp;gt; 'root',
		),
	),
);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Cette configuration est adapt&amp;eacute;e au type de connexion PDO. Il faut l&amp;rsquo;adapter au type MySQL et &amp;agrave; vos propres informations de connexion. Remplacez par le code ci-dessous en modifiant votre identifiant et votre mot de passe :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code193&quot; class=&quot;cm-s-default&quot;&gt;return array(
	'default' =&amp;gt; array(
		'connection'  =&amp;gt; array(
		    'hostname'   =&amp;gt; 'localhost',
		    'database'   =&amp;gt; 'tuto_agenda',
			'username'   =&amp;gt; 'IDENTIFIANT',
			'password'   =&amp;gt; 'MOT DE PASSE',
		),
	),
);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;La configuration de la base de donn&amp;eacute;es est normalement maintenant termin&amp;eacute;e. Il est temps de passer &amp;agrave; la cr&amp;eacute;ation de l'agenda.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Le principe&lt;/h2&gt;
&lt;h3&gt;1.&amp;nbsp;G&amp;eacute;n&amp;eacute;ration de code par Scaffold&lt;/h3&gt;
&lt;p&gt;Nous allons maintenant g&amp;eacute;n&amp;eacute;rer un code de base, qui va nous permettre d&amp;rsquo;avoir un aper&amp;ccedil;u du fonctionnement de FuelPHP. Il existe, dans beaucoup de frameworks (comme Rails), la possibilit&amp;eacute; de g&amp;eacute;n&amp;eacute;rer du code via &lt;a href=&quot;http://en.wikipedia.org/wiki/Scaffolding&quot; target=&quot;_blank&quot;&gt;Scaffold&lt;/a&gt;. Ce code permet de g&amp;eacute;rer les actions de base d&amp;rsquo;un objet (visualisation, cr&amp;eacute;ation, modification, suppression - &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;CRUD&lt;/strong&gt;&lt;/span&gt; en anglais). C&amp;rsquo;est l&amp;rsquo;id&amp;eacute;al pour avoir une base de d&amp;eacute;veloppement !&lt;/p&gt;
&lt;p&gt;Beaucoup d&amp;rsquo;op&amp;eacute;rations peuvent s&amp;rsquo;effectuer sous FuelPHP avec le script &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Oil&lt;/strong&gt;&lt;/span&gt; (remarquez fuel / oil). Ce script permet notamment de g&amp;eacute;n&amp;eacute;rer des migrations, des mod&amp;egrave;les, des contr&amp;ocirc;leurs... et le scaffolding.&lt;/p&gt;
&lt;p&gt;Un agenda contient notamment une partie o&amp;ugrave; il est possible de g&amp;eacute;rer des notes, qui contiennent un titre et une description. Nous allons g&amp;eacute;n&amp;eacute;rer le code via la ligne de commande suivante (apr&amp;egrave;s s&amp;rsquo;&amp;ecirc;tre rendu dans le r&amp;eacute;pertoire root du projet) :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code194&quot; class=&quot;cm-s-default&quot;&gt;php oil generate scaffold/crud notes titre:string description:text&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez remarquer que l&amp;rsquo;&amp;eacute;criture de cette ligne de commande est assez simple :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code195&quot; class=&quot;cm-s-default&quot;&gt;php oil generate scaffold/crud &amp;lt;NOM DE LA TABLE&amp;gt; &amp;lt;ATTRIBUT&amp;gt;:&amp;lt;TYPE&amp;gt; &amp;lt;ATTRIBUT&amp;gt;:&amp;lt;TYPE&amp;gt; &amp;lt;ATTRIBUT&amp;gt;:&amp;lt;TYPE&amp;gt;...&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Notez que l'extension &lt;strong&gt;scaffold/crud &lt;/strong&gt;indique que l'on souhaite utiliser la structure&amp;nbsp;&lt;strong&gt;CRUD&lt;/strong&gt;. Oil peut g&amp;eacute;n&amp;eacute;rer du code suivant d'autres structure (comme &lt;span class=&quot;inline-code&quot;&gt;orm&lt;/span&gt;). La diff&amp;eacute;rence se fera notamment voir au niveau du code g&amp;eacute;n&amp;eacute;r&amp;eacute; dans les mod&amp;egrave;les (qui n'&amp;eacute;tenderont pas les m&amp;ecirc;mes classes).&lt;/p&gt;
&lt;p&gt;Lorsque la commande est ex&amp;eacute;cut&amp;eacute;e, &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Oil&lt;/strong&gt;&lt;/span&gt; nous indique l&amp;rsquo;ensemble des fichiers qui ont &amp;eacute;t&amp;eacute; modifi&amp;eacute;s :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/74.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez voir qu&amp;rsquo;il y en a un certain nombre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/model/note.php&lt;/strong&gt;&lt;/span&gt; : le mod&amp;egrave;le associ&amp;eacute; aux notes&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/migrations/001_create_notes.php&lt;/strong&gt;&lt;/span&gt; : le fichier migration, qui nous permettra de migrer la base de donn&amp;eacute;e en cr&amp;eacute;ant la table notes.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/controller/notes.php&lt;/strong&gt;&lt;/span&gt; : le contr&amp;ocirc;leur associ&amp;eacute; aux notes&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;tous les fichiers dans fuel/app/views/notes/&lt;/strong&gt;&lt;/span&gt; qui sont les vues associ&amp;eacute;es aux actions&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/template.php&lt;/strong&gt;&lt;/span&gt; qui est la vue impl&amp;eacute;mentant la structure de la page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;2. Migration de la base de donn&amp;eacute;es&lt;/h3&gt;
&lt;p&gt;Si le fichier migration a bel et bien &amp;eacute;t&amp;eacute; g&amp;eacute;n&amp;eacute;r&amp;eacute;, la table n&amp;rsquo;a pas &amp;eacute;t&amp;eacute; cr&amp;eacute;&amp;eacute;e pour autant. Il y a dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Oil&lt;/strong&gt;&lt;/span&gt; une commande permettant d&amp;rsquo;&amp;eacute;x&amp;eacute;cuter ces fichiers migration.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code196&quot; class=&quot;cm-s-default&quot;&gt;php oil refine migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Oil&lt;/strong&gt;&lt;/span&gt; permet une libert&amp;eacute; beaucoup plus grande au niveau des migrations, nous y reviendrons plus tard.&lt;/p&gt;
&lt;p&gt;Une fois la commande execut&amp;eacute;e, vous pouvez voir que la base de donn&amp;eacute;es n&amp;rsquo;est plus vide. Elle contient maintenant deux tables :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/66.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Il y a la table &lt;span class=&quot;inline-code&quot;&gt;migration&lt;/span&gt;, qui enregistre quelles migrations ont &amp;eacute;t&amp;eacute; effectu&amp;eacute;es. Nous y reviendrons plus tard.&lt;/p&gt;
&lt;p&gt;Il y a ensuite la table &lt;span class=&quot;inline-code&quot;&gt;notes&lt;/span&gt; que nous voulions cr&amp;eacute;er. Jetons un coup d&amp;rsquo;&amp;oelig;il &amp;agrave; la structure :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/67.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A partir des deux colonnes que nous avons sp&amp;eacute;cifi&amp;eacute;es &amp;agrave; &lt;span class=&quot;inline-code&quot;&gt;Oil&lt;/span&gt; pour le scaffold (titre et description), il en a g&amp;eacute;n&amp;eacute;r&amp;eacute; cinq :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;id&lt;/span&gt; : identifiant de la note avec son index primary associ&amp;eacute;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;titre&lt;/span&gt; : le titre de la note. Nous avons sp&amp;eacute;cifi&amp;eacute; un type string, vous savez maintenant que l&amp;rsquo;&amp;eacute;quivalence MySQL est varchar(255)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;description&lt;/span&gt; : la description de la note&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;created_at&lt;/span&gt; : date de cr&amp;eacute;ation de la note. Est g&amp;eacute;r&amp;eacute;e par d&amp;eacute;faut dans le mod&amp;egrave;le.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;updated_at&lt;/span&gt; : date de modification de la note. Est g&amp;eacute;r&amp;eacute;e par d&amp;eacute;faut dans le mod&amp;egrave;le.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A noter qu&amp;rsquo;il est possible de d&amp;eacute;sactiver la cr&amp;eacute;ation des colonnes &lt;span class=&quot;inline-code&quot;&gt;created_at&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;updated_at&lt;/span&gt; en &amp;eacute;ditant le fichier de migration (si vous g&amp;eacute;n&amp;eacute;rez le mod&amp;egrave;le via &lt;span class=&quot;inline-code&quot;&gt;generate model&lt;/span&gt;, il y a aussi l&amp;rsquo;option &lt;span class=&quot;inline-code&quot;&gt;--no-timestamp&lt;/span&gt;, mais pour le moment elle ne semble pas prise en compte pour le scaffolding).&lt;/p&gt;
&lt;p&gt;La pr&amp;eacute;sence de ces colonnes n&amp;rsquo;est pas g&amp;ecirc;nante et sera probablement utile, donc laissons les.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;3. Aper&amp;ccedil;u&lt;/h3&gt;
&lt;p&gt;La page d&amp;rsquo;accueil n&amp;rsquo;a toujours pas chang&amp;eacute;, mais il est possible maintenant d&amp;rsquo;acc&amp;eacute;der aux notes via l&amp;rsquo;adresse suivante (si vous avez suivi &lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot; target=&quot;_blank&quot;&gt;l&amp;rsquo;installation de Julian&lt;/a&gt;) :&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes&lt;/strong&gt;&lt;/span&gt; si la redirection est activ&amp;eacute;e&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/index.php/notes&lt;/strong&gt;&lt;/span&gt; sinon&lt;/p&gt;
&lt;p&gt;Le tout doit normalement ressembler &amp;agrave; :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/76.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Liste des notes&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/78.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Cr&amp;eacute;ation / &amp;eacute;dition d'une note&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/77.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Vue d'une note&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;Le code g&amp;eacute;n&amp;eacute;r&amp;eacute; g&amp;egrave;re m&amp;ecirc;me les notifications :&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/80.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Apr&amp;egrave;s mise &amp;agrave; jour d'une note&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot;&gt;4. Le code g&amp;eacute;n&amp;eacute;r&amp;eacute;&lt;/h3&gt;
&lt;p&gt;Maintenant que le syst&amp;egrave;me fonctionne, nous pouvons jeter un coup d&amp;rsquo;&amp;oelig;il au code g&amp;eacute;n&amp;eacute;r&amp;eacute;.&lt;/p&gt;
&lt;p&gt;Le scaffold a g&amp;eacute;n&amp;eacute;r&amp;eacute; un mod&amp;egrave;le, situ&amp;eacute; dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/model/note.php&lt;/strong&gt;&lt;/span&gt; qui contient :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code197&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Model_Note extends Model_Crud
{
	protected static $_table_name = 'notes';
	
	public static function validate($factory)
	{
		$val = Validation::forge($factory);
		$val-&amp;gt;add_field('titre', 'Titre', 'required|max_length[255]');
		$val-&amp;gt;add_field('description', 'Description', 'required');

		return $val;
	}

}
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
Le contenu est assez simple, car notre mod&amp;egrave;le &amp;eacute;tend la classe &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Model_Crud&lt;/strong&gt;&lt;/span&gt;, qui contient d&amp;eacute;j&amp;agrave; les fonctions de bases, nous permettant de manipuler l&amp;rsquo;objet dans le code. Il y a une seule variable, &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$_table_name&lt;/strong&gt;&lt;/span&gt; qui, comme son nom l&amp;rsquo;indique, d&amp;eacute;finit le nom de la table associ&amp;eacute;e au mod&amp;egrave;le. Il y a aussi une fonction, &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;validate&lt;/strong&gt;&lt;/span&gt;, qui permet d'imposer des conditions lors de la sauvegarde d'un &amp;eacute;l&amp;eacute;ment. Par exemple, lors de la sauvegarde d'une note, le titre ne doit pas &amp;ecirc;tre vide et sa longueur ne doit pas d&amp;eacute;passer 255 caract&amp;egrave;res. La description elle aussi ne doit pas &amp;ecirc;tre vide. Il est possible d'avoir dans ce domaine un degr&amp;eacute; beaucoup plus grand de libert&amp;eacute;, nous y reviendrons plus tard.&lt;br /&gt;
&lt;p&gt;Le scaffold a aussi g&amp;eacute;n&amp;eacute;r&amp;eacute; un contr&amp;ocirc;leur, situ&amp;eacute; dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/classes/controller/notes.php&lt;/strong&gt;&lt;/span&gt;, qui contient (j&amp;rsquo;ai r&amp;eacute;sum&amp;eacute; certaines actions) :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code198&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php
class Controller_Notes extends Controller_Template 
{

	public function action_index()
	{
		$data['notes'] = Model_Note::find_all();
		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Notes&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/index', $data);

	}

	public function action_view($id = null)
	{
		$data['note'] = Model_Note::find_by_pk($id);

		$this-&amp;gt;template-&amp;gt;title = &amp;quot;Note&amp;quot;;
		$this-&amp;gt;template-&amp;gt;content = View::forge('notes/view', $data);

	}

	public function action_create($id = null)
	{
		//...
	}

	public function action_edit($id = null)
	{
		//...
	}

	public function action_delete($id = null)
	{
		//...

	}


}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut voir que le contr&amp;ocirc;leur est compos&amp;eacute; de cinq fonctions, commen&amp;ccedil;ant toutes par &lt;strong&gt;&lt;span class=&quot;inline-code&quot;&gt;action_&lt;/span&gt;&lt;/strong&gt;. Il s&amp;rsquo;agit des actions du contr&amp;ocirc;leur. Si, par exemple, vous vous rendez sur :&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/create&lt;/strong&gt;&lt;/span&gt; ou&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/index.php/notes/create&lt;/strong&gt;&lt;/span&gt; sans redirection&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est la fonction &lt;span class=&quot;inline-code&quot;&gt;action_create&lt;/span&gt; qui sera appel&amp;eacute;e dans le contr&amp;ocirc;leur.&lt;/p&gt;
&lt;p&gt;Quant &amp;agrave; l&amp;rsquo;adresse :&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;elle est &amp;eacute;quivalente (par d&amp;eacute;faut) &amp;agrave; l&amp;rsquo;adresse :&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/index&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;Donc appelera bien l&amp;rsquo;action &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;action_index&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Analysons la fonction &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt; (qui, comme vous pouvez le d&amp;eacute;duire de l&amp;rsquo;adresse, liste l&amp;rsquo;ensemble des notes qui ont &amp;eacute;t&amp;eacute; cr&amp;eacute;&amp;eacute;es) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La premi&amp;egrave;re ligne charge l&amp;rsquo;ensemble des notes gr&amp;acirc;ce &amp;agrave; la fonction statique &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;find_all&lt;/strong&gt;&lt;/span&gt;. Cette fonction peut bien s&amp;ucirc;r recevoir d&amp;rsquo;autres param&amp;egrave;tres, je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/model_crud/methods.html#/method_find_all&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;La seconde et la troisi&amp;egrave;me lignes modifient toutes les deux des attributs de &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$this-&amp;gt;template&lt;/strong&gt;&lt;/span&gt;, un attribut &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;title&lt;/strong&gt;&lt;/span&gt; (qui est vraisemblablement le titre de la page) et un attribut &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;content&lt;/strong&gt;&lt;/span&gt;, auquel est affect&amp;eacute;e la vue. Je reviendrai un peu plus tard sur cette affectation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;objet qui a &amp;eacute;t&amp;eacute; modifi&amp;eacute; est l&amp;rsquo;instanciation d&amp;rsquo;un template (qui est la structure de la page). Pour faire court, les attributs de cet objet vont pouvoir &amp;ecirc;tre r&amp;eacute;cup&amp;eacute;r&amp;eacute;s par le template. Ce template a lui aussi &amp;eacute;t&amp;eacute; g&amp;eacute;n&amp;eacute;r&amp;eacute; via le scaffold. Il est pr&amp;eacute;sent dans l&amp;rsquo;adresse &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/template.php&lt;/strong&gt;&lt;/span&gt;. Son contenu est le suivant (j&amp;rsquo;ai r&amp;eacute;sum&amp;eacute; le style pour plus de lisibilit&amp;eacute;) :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code199&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
	&amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;
	&amp;lt;title&amp;gt;&amp;lt;?php echo $title; ?&amp;gt;&amp;lt;/title&amp;gt;
	&amp;lt;?php echo Asset::css('bootstrap.css'); ?&amp;gt;
	&amp;lt;style&amp;gt;
		body { margin: 40px; }
	&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
	&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
		&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
			&amp;lt;div class=&amp;quot;span16&amp;quot;&amp;gt;
				&amp;lt;h1&amp;gt;&amp;lt;?php echo $title; ?&amp;gt;&amp;lt;/h1&amp;gt;
				&amp;lt;hr&amp;gt;
&amp;lt;?php if (Session::get_flash('success')): ?&amp;gt;
				&amp;lt;div class=&amp;quot;alert-message success&amp;quot;&amp;gt;
					&amp;lt;p&amp;gt;
					&amp;lt;?php echo implode('&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;', (array) Session::get_flash('success')); ?&amp;gt;
					&amp;lt;/p&amp;gt;
				&amp;lt;/div&amp;gt;
&amp;lt;?php endif; ?&amp;gt;
&amp;lt;?php if (Session::get_flash('error')): ?&amp;gt;
				&amp;lt;div class=&amp;quot;alert-message error&amp;quot;&amp;gt;
					&amp;lt;p&amp;gt;
					&amp;lt;?php echo implode('&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;', (array) Session::get_flash('error')); ?&amp;gt;
					&amp;lt;/p&amp;gt;
				&amp;lt;/div&amp;gt;
&amp;lt;?php endif; ?&amp;gt;
			&amp;lt;/div&amp;gt;
			&amp;lt;div class=&amp;quot;span16&amp;quot;&amp;gt;
&amp;lt;?php echo $content; ?&amp;gt;
			&amp;lt;/div&amp;gt;
		&amp;lt;/div&amp;gt;
		&amp;lt;footer&amp;gt;
			&amp;lt;p class=&amp;quot;pull-right&amp;quot;&amp;gt;Page rendered in {exec_time}s using {mem_usage}mb of memory.&amp;lt;/p&amp;gt;
			&amp;lt;p&amp;gt;
				&amp;lt;a href=&amp;quot;http://fuelphp.com&amp;quot;&amp;gt;FuelPHP&amp;lt;/a&amp;gt; is released under the MIT license.&amp;lt;br&amp;gt;
				&amp;lt;small&amp;gt;Version: &amp;lt;?php echo e(Fuel::VERSION); ?&amp;gt;&amp;lt;/small&amp;gt;
			&amp;lt;/p&amp;gt;
		&amp;lt;/footer&amp;gt;
	&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Ainsi, la valeur de l&amp;rsquo;attribut &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$this-&amp;gt;template-&amp;gt;title&lt;/strong&gt;&lt;/span&gt; est accessible via la variable &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$title&lt;/strong&gt;&lt;/span&gt; dans le template. Si on modifie dans &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code200&quot; class=&quot;cm-s-default&quot;&gt;$this-&amp;gt;template-&amp;gt;title = &amp;quot;Mes notes&amp;quot;;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lorsqu&amp;rsquo;on se rendra de nouveau sur &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/&lt;/strong&gt;&lt;/span&gt;, le titre aura &amp;eacute;t&amp;eacute; modifi&amp;eacute; :&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/81.png&quot; alt=&quot;&quot; width=&quot;550&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sachez qu&amp;rsquo;il est possible de modifier tous les attributs de &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template&lt;/span&gt; (comme &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;description&lt;/span&gt; par exemple). Cet attribut sera alors accessible en tant que variable (&lt;span class=&quot;inline-code&quot;&gt;$description&lt;/span&gt;) dans le template. Il est aussi possible de changer de template, nous y reviendrons plus tard.&lt;/p&gt;
&lt;p&gt;Revenons au contr&amp;ocirc;leur, la derni&amp;egrave;re affectation, comme je le disais, affecte le contenu de la vue :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code201&quot; class=&quot;cm-s-default&quot;&gt;$this-&amp;gt;template-&amp;gt;content = View::forge('notes/index', $data);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;View::forge&lt;/strong&gt;&lt;/span&gt; retourne la vue situ&amp;eacute;e dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/index.php&lt;/strong&gt;&lt;/span&gt; avec les variables d&amp;eacute;finies dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$data&lt;/strong&gt;&lt;/span&gt;. Jetons un coup d&amp;rsquo;oeil &amp;agrave; ce fichier :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code202&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;h2&amp;gt;Listing Notes&amp;lt;/h2&amp;gt;
&amp;lt;br&amp;gt;
&amp;lt;?php if ($notes): ?&amp;gt;
&amp;lt;table class=&amp;quot;zebra-striped&amp;quot;&amp;gt;
	&amp;lt;thead&amp;gt;
		&amp;lt;tr&amp;gt;
			&amp;lt;th&amp;gt;Titre&amp;lt;/th&amp;gt;
			&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
			&amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
		&amp;lt;/tr&amp;gt;
	&amp;lt;/thead&amp;gt;
	&amp;lt;tbody&amp;gt;
&amp;lt;?php foreach ($notes as $note): ?&amp;gt;		&amp;lt;tr&amp;gt;

			&amp;lt;td&amp;gt;&amp;lt;?php echo $note-&amp;gt;titre; ?&amp;gt;&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;&amp;lt;?php echo $note-&amp;gt;description; ?&amp;gt;&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;
				&amp;lt;?php echo Html::anchor('notes/view/'.$note-&amp;gt;id, 'View'); ?&amp;gt; |
				&amp;lt;?php echo Html::anchor('notes/edit/'.$note-&amp;gt;id, 'Edit'); ?&amp;gt; |
				&amp;lt;?php echo Html::anchor('notes/delete/'.$note-&amp;gt;id, 'Delete', array('onclick' =&amp;gt; &amp;quot;return confirm('Are you sure?')&amp;quot;)); ?&amp;gt;

			&amp;lt;/td&amp;gt;
		&amp;lt;/tr&amp;gt;
&amp;lt;?php endforeach; ?&amp;gt;	&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;?php else: ?&amp;gt;
&amp;lt;p&amp;gt;No Notes.&amp;lt;/p&amp;gt;

&amp;lt;?php endif; ?&amp;gt;&amp;lt;p&amp;gt;
	&amp;lt;?php echo Html::anchor('notes/create', 'Add new Note', array('class' =&amp;gt; 'btn success')); ?&amp;gt;

&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;View::forge&lt;/strong&gt;&lt;/span&gt; retourne donc le contenu du fichier execut&amp;eacute; en PHP avec les variables d&amp;eacute;finies dans &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$data&lt;/strong&gt;&lt;/span&gt;. Ainsi &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$data[&amp;lsquo;notes&amp;rsquo;]&lt;/strong&gt;&lt;/span&gt; est accessible via la variable &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;$notes&lt;/strong&gt;&lt;/span&gt; dans la vue &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;index.php&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;On peut remarquer au passage dans le fichier de nombreux appels &amp;agrave; la fonction &lt;span class=&quot;inline-code&quot;&gt;Html::anchor&lt;/span&gt;. Il s&amp;rsquo;agit d&amp;rsquo;un helper, c&amp;rsquo;est &amp;agrave; dire d&amp;rsquo;une fonction retournant des bouts de code en Html. Dans ce cas ci il s&amp;rsquo;agit d&amp;rsquo;un lien, avec comme classes css &lt;span class=&quot;inline-code&quot;&gt;btn success&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code203&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php echo Html::anchor('notes/create', 'Add new Note', array('class' =&amp;gt; 'btn success')); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;est &amp;eacute;quivalent &amp;agrave;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code204&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;a class=&amp;quot;btn success&amp;quot; href=&amp;quot;http://localhost/mon_site_fuel/public/notes/create&amp;quot;&amp;gt;Add new Note&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il est parfaitement possible de s&amp;rsquo;en passer et d&amp;rsquo;&amp;eacute;crire ce code HTML directement. &lt;span class=&quot;inline-code&quot;&gt;Html::anchor&lt;/span&gt; permet cependant de se simplifier la vie (vous pouvez voir qu&amp;rsquo;il &amp;eacute;crit l&amp;rsquo;url compl&amp;egrave;te), et l&amp;rsquo;utilisation d&amp;rsquo;helpers de mani&amp;egrave;re g&amp;eacute;n&amp;eacute;rale permet d&amp;rsquo;am&amp;eacute;liorer la maintenabilit&amp;eacute; (on peut imaginer faire une surcouche &amp;agrave; &lt;span class=&quot;inline-code&quot;&gt;Html::anchor&lt;/span&gt; pour passer de liens directs &amp;agrave; des requ&amp;ecirc;tes en ajax par exemple, le tout en ne modifiant qu&amp;rsquo;un seul bout de code).&lt;/p&gt;
&lt;p&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;Html::anchor&lt;/span&gt; supporte d&amp;rsquo;autres param&amp;egrave;tres. Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/html.html#/method_anchor&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Pour r&amp;eacute;sumer :&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lorsqu&amp;rsquo;un utilisateur se rend dans une adresse d&amp;rsquo;un site fuelPHP&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Une fonction du contr&amp;ocirc;leur &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;notes&lt;/strong&gt;&lt;/span&gt; est appel&amp;eacute;e (le cas pr&amp;eacute;sent &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;Cette fonction charge les variables qui lui sont n&amp;eacute;cessaires, affecte les attributs de &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template&lt;/span&gt; (que ce soit directement une chaine de caract&amp;egrave;re ou le retour d&amp;rsquo;un &lt;span class=&quot;inline-code&quot;&gt;View::Forge&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;Le template est affich&amp;eacute; &amp;agrave; l&amp;rsquo;utilisateur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si vous avez eu l&amp;rsquo;occasion d&amp;rsquo;utiliser d&amp;rsquo;autres framework, vous avez probablement remarqu&amp;eacute; qu&amp;rsquo;il n&amp;rsquo;est souvent pas n&amp;eacute;cessaire de sp&amp;eacute;cifier la vue dans l&amp;rsquo;action. Par exemple dans l&amp;rsquo;action &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt; :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code205&quot; class=&quot;cm-s-default&quot;&gt;public function action_index()
{
	$data['notes'] = Model_Note::find_all();
	$this-&amp;gt;template-&amp;gt;title = &amp;quot;Mes notes&amp;quot;;
	$this-&amp;gt;template-&amp;gt;content = View::forge('notes/index', $data);

}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il n&amp;rsquo;est pas l&amp;agrave; n&amp;eacute;cessaire de d&amp;eacute;finir &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;title&lt;/span&gt;, ni &lt;span class=&quot;inline-code&quot;&gt;$this-&amp;gt;template-&amp;gt;content&lt;/span&gt; (pour chaque action, une vue est attibu&amp;eacute;e par d&amp;eacute;faut). Cette politique permet de limiter les r&amp;eacute;p&amp;eacute;titions dans le code.&lt;/p&gt;
&lt;p&gt;Avec FuelPHP, ce comportement n&amp;rsquo;est pas disponible par d&amp;eacute;faut mais, gr&amp;acirc;ce &amp;agrave; la fonction &lt;span class=&quot;inline-code&quot;&gt;after&lt;/span&gt;, que nous verrons plus tard, il est possible de l&amp;rsquo;imiter. C&amp;rsquo;est donc avant tout une force du framework, qui laisse une libert&amp;eacute; plus grande au niveau des templates.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;5. Param&amp;egrave;tres et actions&lt;/h3&gt;
&lt;p&gt;Le traitement des param&amp;egrave;tres dans les actions est un point important, car il va vous permettre notamment d&amp;rsquo;interagir avec l&amp;rsquo;internaute.&lt;/p&gt;
&lt;h4&gt;a. Via les param&amp;egrave;tres d&amp;rsquo;une action&lt;/h4&gt;
&lt;p&gt;Jetons un coup d&amp;rsquo;oeil &amp;agrave; l&amp;rsquo;action &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;action_view&lt;/strong&gt;&lt;/span&gt; (qui permet de visualiser une note en particulier) dans le contr&amp;ocirc;leur notes :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code206&quot; class=&quot;cm-s-default&quot;&gt;public function action_view($id = null)
{
	$data['note'] = Model_Note::find_by_pk($id);

	$this-&amp;gt;template-&amp;gt;title = &amp;quot;Note&amp;quot;;
	$this-&amp;gt;template-&amp;gt;content = View::forge('notes/view', $data);

}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;On peut remarquer la pr&amp;eacute;sence d&amp;rsquo;un param&amp;egrave;tre dans la d&amp;eacute;claration, contrairement &amp;agrave; &lt;span class=&quot;inline-code&quot;&gt;action_index&lt;/span&gt;. Lorsqu&amp;rsquo;on fait appel &amp;agrave; l&amp;rsquo;action &lt;span class=&quot;inline-code&quot;&gt;action_view&lt;/span&gt;, c&amp;rsquo;est qu&amp;rsquo;on veut charger une note en particulier, que l&amp;rsquo;on r&amp;eacute;cup&amp;egrave;re gr&amp;acirc;ce &amp;agrave; l&amp;rsquo;identifiant.&lt;/p&gt;
&lt;p&gt;Ainsi, lorsque l&amp;rsquo;utilisateur acc&amp;eacute;dera &amp;agrave; l&amp;rsquo;adresse :&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;http://localhost/mon_site_fuel/public/notes/view/1&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;action_view&lt;/span&gt; sera appel&amp;eacute;e avec comme param&amp;egrave;tre &lt;span class=&quot;inline-code&quot;&gt;$id = 1&lt;/span&gt;. Il est parfaitement possible de multiplier le nombre de param&amp;egrave;tres.&lt;/p&gt;
&lt;h4&gt;b.&amp;nbsp;Via la classe Input&lt;/h4&gt;
&lt;p&gt;Si vous jetez un coup d&amp;rsquo;&amp;oelig;il &amp;agrave; la fonction &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;action_create&lt;/strong&gt;&lt;/span&gt;, vous pouvez remarquer la pr&amp;eacute;sence de &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;Input::post&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;inline-code&quot;&gt;Input::post&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;Input::get&lt;/span&gt; permettent de r&amp;eacute;cup&amp;eacute;rer les valeurs &lt;span class=&quot;inline-code&quot;&gt;$_POST&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;$_GET&lt;/span&gt; respectivement. Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/input.html#/method_post&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;6. Les partials&lt;/h3&gt;
&lt;p&gt;Si vous consultez les fichiers vues &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/edit.php&lt;/strong&gt;&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/create.php&lt;/strong&gt;&lt;/span&gt;, vous remarquez une ligne en commun dans les deux fichiers :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code207&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php echo render('notes/_form'); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Ils incluent tous les deux un partial, c&amp;rsquo;est &amp;agrave; dire un bout de vue. En effet, si on compare le formulaire de cr&amp;eacute;ation et d&amp;rsquo;&amp;eacute;dition,&amp;nbsp;les deux vues sont tr&amp;egrave;s similaires. Elles font donc appel toutes les deux &amp;agrave; un m&amp;ecirc;me partial (bout de vue), reprenant le formulaire. L&amp;rsquo;appel &amp;agrave; des partials permet de limiter la r&amp;eacute;p&amp;eacute;tition du code et donc d&amp;rsquo;am&amp;eacute;liorer la maintenabilit&amp;eacute; d&amp;rsquo;un logiciel. A utiliser tant que possible !&lt;/p&gt;
&lt;p&gt;La fonction &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;render&lt;/strong&gt;&lt;/span&gt; permet donc de renvoyer le contenu execut&amp;eacute; d&amp;rsquo;un partial, dans notre cas &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/views/notes/_form.php&lt;/strong&gt;&lt;/span&gt;. Voici le contenu :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code208&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;?php echo Form::open(array('class' =&amp;gt; 'form-stacked')); ?&amp;gt;

	&amp;lt;fieldset&amp;gt;
		&amp;lt;div class=&amp;quot;clearfix&amp;quot;&amp;gt;
			&amp;lt;?php echo Form::label('Titre', 'titre'); ?&amp;gt;

			&amp;lt;div class=&amp;quot;input&amp;quot;&amp;gt;
				&amp;lt;?php echo Form::input('titre', Input::post('titre', isset($note) ? $note-&amp;gt;titre : ''), array('class' =&amp;gt; 'span6')); ?&amp;gt;

			&amp;lt;/div&amp;gt;
		&amp;lt;/div&amp;gt;
		&amp;lt;div class=&amp;quot;clearfix&amp;quot;&amp;gt;
			&amp;lt;?php echo Form::label('Description', 'description'); ?&amp;gt;

			&amp;lt;div class=&amp;quot;input&amp;quot;&amp;gt;
				&amp;lt;?php echo Form::textarea('description', Input::post('description', isset($note) ? $note-&amp;gt;description : ''), array('class' =&amp;gt; 'span10', 'rows' =&amp;gt; 8)); ?&amp;gt;

			&amp;lt;/div&amp;gt;
		&amp;lt;/div&amp;gt;
		&amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;
			&amp;lt;?php echo Form::submit('submit', 'Save', array('class' =&amp;gt; 'btn primary')); ?&amp;gt;

		&amp;lt;/div&amp;gt;
	&amp;lt;/fieldset&amp;gt;
&amp;lt;?php echo Form::close(); ?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;A noter qu&amp;rsquo;on acc&amp;egrave;de &amp;agrave; la variable &lt;span class=&quot;inline-code&quot;&gt;$note&lt;/span&gt;. En effet, cette variable est accessible car dans l'action &lt;strong&gt;edit &lt;/strong&gt;on peut voir cette ligne :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code312&quot; class=&quot;cm-s-default&quot;&gt;$this-&amp;gt;template-&amp;gt;set_global('note', $note, false);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Cette variable est affect&amp;eacute;e au template en tant que globale et est donc accessible &amp;agrave; toutes les vues, sans avoir &amp;agrave; la passer dans leurs param&amp;egrave;tres. Ce comportement peut &amp;ecirc;tre pratique si on a une variable qu'on veut acc&amp;eacute;der partout (comme l'utilisateur enregistr&amp;eacute; en session ou une configuration globale), mais est peu recommand&amp;eacute;e pour les autres cas car elle r&amp;eacute;duit la lisibilit&amp;eacute; du code.&lt;/p&gt;
&lt;p&gt;Le partial fait notamment appel &amp;agrave; la classe helper &lt;span class=&quot;inline-code&quot;&gt;Form&lt;/span&gt;, qui permet d&amp;rsquo;instancier un formulaire et des champs en HTML. Je vous invite &amp;agrave; consulter &lt;a href=&quot;http://docs.fuelphp.com/classes/form.html&quot; target=&quot;_blank&quot;&gt;la documentation associ&amp;eacute;e&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;J'esp&amp;egrave;re que cet article vous a permis de vous lancer sur FuelPHP. N'h&amp;eacute;sitez pas &amp;agrave; me contacter en commentaire ou &lt;a href=&quot;http://twitter.com/sdrdis&quot; target=&quot;_blank&quot;&gt;sur Twitter&lt;/a&gt; si vous avez des questions. Dans un article prochain, nous passerons &amp;agrave; l'action ! Avec les connaissances acquises dans cet article, nous finaliserons notre agenda en am&amp;eacute;liorant l'affichage, en organisant un menu, en complexifiant notre mod&amp;egrave;le de donn&amp;eacute;es et, enfin, en mettant en place un syst&amp;egrave;me d'authentification.&lt;/p&gt;
&lt;div id=&quot;_mcePaste&quot; class=&quot;mcePaste&quot; style=&quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;&quot;&gt;https://fuelphp.com/blog/2011/12/version-1-1-finally-lands&lt;/div&gt;&lt;/div&gt;</description>
       <dc:creator>Sébastien Drouyer </dc:creator>
       <pubDate>Wed, 14 Dec 2011 10:37:00 +0100</pubDate>
   </item>
   <item>
       <title>Pourquoi j'ai besoin d'un Dribbble for Words</title>
       <link>http://www.novius-labs.com/pourquoi-besoin-dribbble-for-words,33.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_33_vignette.png</img>
       <guid>http://www.novius-labs.com/pourquoi-besoin-dribbble-for-words,33.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_33_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;A la question &quot;quels livres doit lire un créateur de sites web&quot;, je réponds &lt;a href=&quot;http://www.jjg.net/elements&quot; target=&quot;_blank&quot;&gt;&lt;i&gt;Elements of User Experience&lt;/i&gt;&lt;/a&gt; de Jesse James Garett et &lt;a href=&quot;http://gettingreal.37signals.com&quot; target=&quot;_blank&quot;&gt;&lt;i&gt;Getting Real&lt;/i&gt;&lt;/a&gt; de 37signal. Oui, ils ont tous deux plus de cinq ans, je vois ça comme un atout. Il y a cinq ans donc, Jason Fried nous disait : &lt;a href=&quot;http://gettingreal.37signals.com/ch09_Copywriting_is_Interface_Design.php&quot; target=&quot;_blank&quot;&gt;&lt;i&gt;copywriting is interface design&lt;/i&gt;&lt;/a&gt;. Cinq ans. Il serait temps de passer à l'action.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;h2&gt;Combien de pixels mesure ton interface&amp;nbsp;?&lt;/h2&gt;
&lt;p&gt;En septembre dernier, Des Traynor d'Intercom nous pr&amp;eacute;sentait &lt;a href=&quot;http://contrast.ie/blog/the-language-of-interfaces/&quot; target=&quot;_blank&quot;&gt;son id&amp;eacute;e d'un &lt;em&gt;Dribbble for Words&lt;/em&gt;&lt;/a&gt; &amp;agrave; l'occasion de sa conf&amp;eacute;rence &lt;em&gt;&lt;a href=&quot;http://speakerdeck.com/u/destraynor/p/the-language-of-interfaces&quot; target=&quot;_blank&quot;&gt;The Language of Interfaces&lt;/a&gt;&lt;/em&gt; &amp;agrave; Londres. &lt;a href=&quot;http://dribbble.com&quot; target=&quot;_blank&quot;&gt;Dribbble&lt;/a&gt; est une communaut&amp;eacute; populaire, r&amp;eacute;serv&amp;eacute;e aux designers, o&amp;ugrave; sont publi&amp;eacute;s et comment&amp;eacute;s des pixels. On y parle image sous toutes ses formes&amp;nbsp;: logo, identit&amp;eacute; visuelle, &lt;em&gt;print&lt;/em&gt;, j'en passe, et &lt;a href=&quot;http://dribbble.com/tags/ui&quot; target=&quot;_blank&quot;&gt;UI&lt;/a&gt;. Je partage l'opinion de Des Traynor &amp;agrave; l'endroit de Dribbble&amp;nbsp;: je n'ai absolument rien contre, mais il s'agit de graphisme, ni plus, ni moins.&lt;/p&gt;
&lt;p&gt;Ainsi, pour que les interfaces ne soient plus exprim&amp;eacute;es uniquement en pixels, compl&amp;eacute;tons Dribbble d'un Wordddle, d'un Scribbble ou encore d'un Palabbbras (quitte &amp;agrave; parler langue, pourquoi se limiter &amp;agrave; l'anglais&amp;nbsp;?). Voil&amp;agrave; ce que j'y ferais.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Ma semaine sur Palabbbras&lt;/h2&gt;
&lt;p&gt;J'aurais commenc&amp;eacute; par voir cette proposition de l'&amp;eacute;quipe de &lt;a href=&quot;http://www.capitainetrain.com&quot; target=&quot;_blank&quot;&gt;Capitaine Train&lt;/a&gt; (au passage, merci Capitaine Train de m'avoir fait oublier Voyages SNCF). J'aurais bien s&amp;ucirc;r r&amp;eacute;agi, voyez mon commentaire ci-dessous.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/60.png&quot; alt=&quot;Dribbble for Words&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Quelques jours plus tard, &amp;ccedil;'aurait &amp;eacute;t&amp;eacute; &amp;agrave; mon tour de faire part d'un de nos probl&amp;egrave;mes et de notre solution. Mon objectif&amp;nbsp;: &amp;eacute;valuer notre proposition en la confrontant &amp;agrave; l'avis d'autres UX designers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/61.png&quot; alt=&quot;Dribbble for Words&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Tout le monde n'est pas convaincu&lt;/h2&gt;
&lt;p&gt;Alors que l'id&amp;eacute;e d'un &lt;em&gt;Dribbble for Words&lt;/em&gt; n'avait que quatre jours, &lt;a href=&quot;http://blog.arc90.com/2011/09/20/interaction-designs-secret-weapon-words/&quot; target=&quot;_blank&quot;&gt;Tim Meany d'Arc90 y r&amp;eacute;agissait n&amp;eacute;gativement&lt;/a&gt;... mais avec beaucoup d'humour. A l'aide d'un dessin g&amp;eacute;nial (remarquez le &quot;1776 views&quot;), il souligne l'importance du contexte. Il doute qu'on puisse discuter d'un texte sans conna&amp;icirc;tre le site ou l'application dont il est issu.&lt;/p&gt;
&lt;p&gt;Loin de moi l'id&amp;eacute;e de remettre en cause le r&amp;ocirc;le central du contexte, mais je pense qu'on peut le r&amp;eacute;sumer, l'expliquer. C'est pourquoi sur mes interfaces de Palabbbras, j'ai int&amp;eacute;gr&amp;eacute; un &quot;notre probl&amp;egrave;me&quot; de m&amp;ecirc;me taille que &quot;notre solution&quot; (contrairement au &lt;em&gt;purpose&lt;/em&gt; de Wordddle, trop discret), ainsi que &quot;voir la solution en action&quot; (les pixels sont ici au service des mots).&lt;/p&gt;
&lt;p&gt;On pourrait m&amp;ecirc;me aller plus loin dans l'explication du contexte, en se basant sur le &lt;em&gt;microcopy framework&lt;/em&gt;, toujours de Des Traynor :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/62.png&quot; alt=&quot;Microcopy framework par Des Traynor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Et vous, qu'en pensez-vous&amp;nbsp;? Qui est partant pour un &lt;em&gt;Dribbble for Words&lt;/em&gt;&amp;nbsp;?&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Thu, 24 Nov 2011 16:20:00 +0100</pubDate>
   </item>
   <item>
       <title>FuelPHP : mise en place de l'environnement</title>
       <link>http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_30_vignette.png</img>
       <guid>http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_30_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;&lt;div style=&quot;float:left;overflow:auto;&quot;&gt;Au programme de cet deuxième article consacré à FuelPHP  :&lt;ul&gt;&lt;li&gt;Installation du framework&lt;/li&gt;&lt;li&gt;Structure des fichiers&lt;/li&gt;&lt;li&gt;Traitement et exécution d'une requête&lt;/li&gt;&lt;li&gt;Configuration de l'application&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br style=&quot;clear: left;&quot; /&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;h2&gt;Installation via la ligne de commande&lt;/h2&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html&quot;&gt;Choix du framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mise en place&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/creation-projet-avec-fuelphp,35.html&quot;&gt;Cr&amp;eacute;ation d'un projet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot;&gt;Application type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html&quot;&gt;Cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html&quot; target=&quot;_blank&quot;&gt;L'ORM : gestion des relations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;Pour les habitu&amp;eacute;s de Git et de la ligne de commande sous Linux, vous pouvez aller faire un tour sur la page de la documentation officielle qui vous explique comment mettre tout &amp;ccedil;a en place : &lt;a href=&quot;http://docs.fuelphp.com/installation/instructions.html&quot; target=&quot;_blank&quot;&gt;http://docs.fuelphp.com/installation/instructions.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pour tous les autres moins dou&amp;eacute;s (comme moi), il y a la m&amp;eacute;thode classique&amp;nbsp;:&lt;/p&gt;
&lt;p&gt;&lt;br style=&quot;clear: both;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Installation manuelle&lt;/h2&gt;
&lt;p&gt;T&amp;eacute;l&amp;eacute;charger la version la plus r&amp;eacute;cente des sources ici&amp;nbsp;: &lt;a href=&quot;http://docs.fuelphp.com/installation/download.html&quot;&gt;http://docs.fuelphp.com/installation/download.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;Agrave; l&amp;rsquo;heure o&amp;ugrave; j&amp;rsquo;&amp;eacute;cris cet article, il existe une version plus r&amp;eacute;cente que je vous recommande&amp;nbsp;: &lt;a href=&quot;https://github.com/downloads/fuel/fuel/fuelphp-v1.1.zip&quot;&gt;https://github.com/downloads/fuel/fuel/fuelphp-v1.1.zip&lt;/a&gt; (sortie le 13 d&amp;eacute;cembre 2011).&lt;/p&gt;
&lt;p&gt;Mettre &amp;ccedil;a dans votre dossier d&amp;rsquo;h&amp;eacute;bergement, par exemple &lt;span class=&quot;inline-code&quot;&gt;c:\wamp\www\mon_site_fuel\&lt;/span&gt; (WampServer sous Windows) ou &lt;span class=&quot;inline-code&quot;&gt;/var/www/mon_site_fuel/&lt;/span&gt; (Linux).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Information s&amp;eacute;curit&amp;eacute; !&lt;/strong&gt;&lt;/span&gt; En th&amp;eacute;orie, seul le r&amp;eacute;pertoire &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;public/&lt;/strong&gt;&lt;/span&gt; doit &amp;ecirc;tre accessible via l&amp;rsquo;URL. Hors, avec notre installation, le r&amp;eacute;pertoire &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/&lt;/strong&gt;&lt;/span&gt; et le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;oil&lt;/strong&gt;&lt;/span&gt; le sont &amp;eacute;galement. Ce qui n'est pas n&amp;eacute;cessaire et pr&amp;eacute;sente un risque de s&amp;eacute;curit&amp;eacute;, car ils ne sont pas pr&amp;eacute;vus pour &amp;ccedil;a.&lt;br /&gt;Pour notre environnement en local, &amp;ccedil;a n'est pas tr&amp;egrave;s grave, mais n&amp;rsquo;utilisez pas cette configuration ailleurs qu&amp;rsquo;en local !&lt;/p&gt;
&lt;p&gt;Pour r&amp;eacute;soudre ce probl&amp;egrave;me de s&amp;eacute;cuit&amp;eacute;, si vous en avez la possibilit&amp;eacute; et que vous savez comment faire, utilisez le r&amp;eacute;pertoire &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;public/&lt;/strong&gt;&lt;/span&gt; en tant que &lt;span class=&quot;inline-code&quot;&gt;Document Root&lt;/span&gt; pour votre installation.&lt;/p&gt;
&lt;p&gt;D&amp;eacute;sormais, si vous allez sur &lt;a href=&quot;http://localhost/mon_site_fuel/public/index.php&quot; target=&quot;_blank&quot;&gt;http://localhost/mon_site_fuel/public/index.php&lt;/a&gt; vous devriez voir la page de bienvenue qui s&amp;rsquo;affiche et vous f&amp;eacute;licite :&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;http://www.novius-labs.com/data/photo/57.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;R&amp;eacute;&amp;eacute;criture d'URL&lt;/h2&gt;
&lt;p&gt;Fuel fournit un fichier &lt;span class=&quot;inline-code&quot;&gt;.htaccess&lt;/span&gt;&amp;nbsp;pour Apache pour utiliser la r&amp;eacute;&amp;eacute;criture d'URL lorsque c'est possible.&lt;/p&gt;
&lt;p&gt;Avec la r&amp;eacute;&amp;eacute;criture, les URL seront de la forme&amp;nbsp;&lt;span class=&quot;inline-code&quot; style=&quot;color: #474d4d;&quot;&gt;http://localhost/mon_site_fuel/public/votre/page/ici&lt;/span&gt;&lt;br /&gt;Sans la r&amp;eacute;&amp;eacute;criture, les URL seront de la forme &lt;span class=&quot;inline-code&quot; style=&quot;color: #474d4d;&quot;&gt;http://localhost/mon_site_fuel/public/&lt;strong&gt;index.php/&lt;/strong&gt;votre/page/ici&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;La r&amp;eacute;&amp;eacute;criture permet donc d'avoir des URL plus jolies en supprimant la partie &lt;span class=&quot;inline-code&quot;&gt;index.php&lt;/span&gt;&amp;nbsp;dans l'URL.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Structure des fichiers propos&amp;eacute;e par d&amp;eacute;faut&lt;/h2&gt;
&lt;p&gt;Avant d&amp;rsquo;aller plus loin, il est important de voir les r&amp;eacute;pertoires qui existent et ce qu&amp;rsquo;ils contiennent&amp;nbsp;:&lt;/p&gt;
&lt;p&gt;Vous trouverez trois choses importantes &amp;agrave; la racine&amp;nbsp;:&lt;img style=&quot;float: right;&quot; src=&quot;http://www.novius-labs.com/data/photo/58.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: le code PHP c&amp;rsquo;est par ici&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;public/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: dossier accessible depuis le navigateur (images, CSS, JavaScript, etc.)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;oil&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: l&amp;rsquo;ex&amp;eacute;cutable ligne de commande de FuelPHP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le r&amp;eacute;pertoire &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/&lt;/strong&gt;&lt;/span&gt; contient trois sous-r&amp;eacute;pertoires importants&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;app/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: votre application (configuration, contr&amp;ocirc;leurs, mod&amp;egrave;les, vues, etc.)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;core/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: le c&amp;oelig;ur de FuelPHP. Nous l&amp;rsquo;appellerons Core.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;packages/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: extensions du Core qui sont s&amp;eacute;par&amp;eacute;es car facultatives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les chemins vers ces trois r&amp;eacute;pertoires sont d&amp;eacute;finis dans le fichier &lt;strong&gt;&lt;span class=&quot;inline-code&quot;&gt;public/index.php&lt;/span&gt;&lt;/strong&gt;, et sont donc modifiables facilement si vous le voulez. :-)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Enfin, la partie importante pour nous (celle que nous allons modifier) se situe dans le dossier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;fuel/app/&lt;/strong&gt;&lt;/span&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;config/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: toute la configuration, notamment le fichier g&amp;eacute;n&amp;eacute;ral &lt;span class=&quot;inline-code&quot;&gt;config.php&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;classes/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: contr&amp;ocirc;leurs, mod&amp;egrave;les, &lt;em&gt;helpers&lt;/em&gt;, logique m&amp;eacute;tier. Quand vous cr&amp;eacute;ez un fichier PHP c&amp;rsquo;est probablement ici qu&amp;rsquo;il trouve sa place&amp;nbsp;!                           
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;controller/&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: les contr&amp;ocirc;leurs&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;model/&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;: les mod&amp;egrave;les utilis&amp;eacute;s par l'ORM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;views/&lt;/strong&gt;&lt;/span&gt; : les vues et&amp;nbsp;&lt;em&gt;templates&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;autres dossiers qui nous concernent moins pour le moment sont &amp;eacute;galement pr&amp;eacute;sents :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;cache/&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;lang/&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;logs/&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;modules/&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assurez-vous juste &amp;agrave; ce que &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;cache/&lt;/strong&gt;&lt;/span&gt; et &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;logs/&lt;/strong&gt;&lt;/span&gt; soient inscriptibles (droits d'&amp;eacute;criture &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;w&lt;/strong&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;R&amp;eacute;pondre &amp;agrave; une requ&amp;ecirc;te de l'internaute&lt;/h2&gt;
&lt;p&gt;Tout commence par &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;public/index.php&lt;/strong&gt;&lt;/span&gt; qui sert de &lt;a href=&quot;http://en.wikipedia.org/wiki/Front_Controller_pattern&quot; target=&quot;_blank&quot;&gt;contr&amp;ocirc;leur frontal&lt;/a&gt; (toutes les requ&amp;ecirc;tes passent par ce fichier) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;Eacute;tape 1, &lt;strong&gt;initialisation :&lt;/strong&gt; 
&lt;ul style=&quot;list-style-type: square;&quot;&gt;
&lt;li&gt;Les constantes vers les trois r&amp;eacute;pertoires principaux sont d&amp;eacute;finies : &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;APPPATH&lt;/strong&gt;&lt;/span&gt; (application), &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;COREPATH&lt;/strong&gt;&lt;/span&gt; (Core FuelPHP) et &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;PKGPATH&lt;/strong&gt;&lt;/span&gt; (packages) ;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Le fichier d'initialisation de l&amp;rsquo;application est inclus : &lt;span class=&quot;inline-code&quot;&gt;APPPATH/bootstrap.php&lt;/span&gt; (cf. ci-dessous pour le d&amp;eacute;tail)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;Eacute;tape 2, &lt;strong&gt;traitement / ex&amp;eacute;cution :&lt;/strong&gt; de la requ&amp;ecirc;te qui g&amp;eacute;n&amp;egrave;re une r&amp;eacute;ponse&lt;/li&gt;
&lt;li&gt;&amp;Eacute;tape 3, &lt;strong&gt;affichage :&lt;/strong&gt; de la r&amp;eacute;ponse g&amp;eacute;n&amp;eacute;r&amp;eacute;e&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Initialisation de l'application&lt;/h3&gt;
&lt;p&gt;Correspond au d&amp;eacute;tail du fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;APPPATH/bootstrap.php&lt;/strong&gt;&lt;/span&gt; :&lt;/p&gt;
&lt;ol style=&quot;list-style-type: lower-roman;&quot;&gt;
&lt;li&gt;Chargement de la classe Autoloader&lt;/li&gt;
&lt;li&gt;Inclusion du fichier &lt;span class=&quot;inline-code&quot;&gt;COREPATH/bootstrap.php&lt;/span&gt; de FuelPHP (en gros, le Core configure l&amp;rsquo;Autoloader pour ses propres classes)&lt;/li&gt;
&lt;li&gt;Configuration et activaton de l&amp;rsquo;Autoloader&lt;/li&gt;
&lt;li&gt;On d&amp;eacute;finit &lt;strong&gt;l&amp;rsquo;environnement&lt;/strong&gt; (d&amp;eacute;veloppement, test / int&amp;eacute;gration, pr&amp;eacute;-prod / stage, production)&lt;/li&gt;
&lt;li&gt;Enfin, &lt;span class=&quot;inline-code&quot;&gt;Fuel::init()&lt;/span&gt;&amp;nbsp;initialise l'application en fonction de l'environnement et de la &lt;strong&gt;configuration&lt;/strong&gt; (fichier &lt;span class=&quot;inline-code&quot;&gt;config.php&lt;/span&gt;)&lt;/li&gt;
&lt;/ol&gt; 
&lt;ul&gt;
&lt;li&gt;Configuration du profiling et du cache&lt;/li&gt;
&lt;li&gt;Configuration de la timezone, de l&amp;rsquo;encodage et de la locale&lt;/li&gt;
&lt;li&gt;Configuration du base URL&lt;/li&gt;
&lt;li&gt;Filtrage des donn&amp;eacute;es GPC (Get, Post et Cookie)&lt;/li&gt;
&lt;li&gt;Active les packages, classes, config et langues &amp;agrave; toujours charger&lt;/li&gt;
&lt;li&gt;Chargement des routes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Traitement et ex&amp;eacute;cution de la requ&amp;ecirc;te&lt;/h3&gt;
&lt;p&gt;L'objectif est de traiter une requ&amp;ecirc;te de l'internaute (appel d'une URL via son navigateur) pour lui afficher une r&amp;eacute;ponse. Cette transformation est le r&amp;ocirc;le du contr&amp;ocirc;leur.&lt;/p&gt;
&lt;p&gt;Correspond au d&amp;eacute;tail de &lt;strong&gt;l&amp;rsquo;&amp;eacute;tape 2&lt;/strong&gt; (Traitement / ex&amp;eacute;cution) du cheminement dans &lt;span class=&quot;inline-code&quot;&gt;public/index.php&lt;/span&gt; :&lt;/p&gt;
&lt;ol style=&quot;list-style-type: lower-roman;&quot;&gt;
&lt;li&gt;D&amp;eacute;termine le bon contr&amp;ocirc;leur en fonction des routes d&amp;eacute;finies&lt;/li&gt;
&lt;li&gt;Cr&amp;eacute;&amp;eacute; l&amp;rsquo;instance du contr&amp;ocirc;leur&lt;/li&gt;
&lt;li&gt;Appelle sa m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;before()&lt;/span&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Ex&amp;eacute;cute l&amp;rsquo;action appropri&amp;eacute;e, qui g&amp;eacute;n&amp;egrave;re la r&amp;eacute;ponse&lt;/li&gt;
&lt;li&gt;Appelle la m&amp;eacute;thode &lt;span class=&quot;inline-code&quot;&gt;after()&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Ceci peut &amp;ecirc;tre r&amp;eacute;p&amp;eacute;t&amp;eacute;e plusieurs fois s&amp;rsquo;il y a des sous-requ&amp;ecirc;tes (&lt;a href=&quot;http://techportal.ibuildings.com/2010/02/22/scaling-web-applications-with-hmvc/&quot; target=&quot;_blank&quot;&gt;HMVC&lt;/a&gt;, nous verrons cette notion dans un article).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Configuration de l&amp;rsquo;application&lt;/h2&gt;
&lt;p&gt;FuelPHP fait partie de l&amp;rsquo;&amp;eacute;cole &amp;laquo; &lt;em&gt;Configuration over convention&lt;/em&gt; &amp;raquo;. En r&amp;eacute;alit&amp;eacute;, ils ont bien des conventions, mais surtout pour ce qui est bas-niveau. Cependant, la configuration est un point central ! Je crois que l&amp;rsquo;important est qu&amp;rsquo;il y a tr&amp;egrave;s peu de magie dans le code. Et qu'au final, il est extr&amp;ecirc;mement simple de comprendre ce que l&amp;rsquo;on fait.&lt;/p&gt;
&lt;p&gt;Les fichiers de configuration sont stock&amp;eacute;s dans le r&amp;eacute;pertoire &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;app/config&lt;/strong&gt;&lt;/span&gt;. La configuration g&amp;eacute;n&amp;eacute;rale de l&amp;rsquo;application se situe elle dans le fichier &lt;strong&gt;&lt;span class=&quot;inline-code&quot;&gt;config.php&lt;/span&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;En voici les options les plus importantes :&lt;img style=&quot;float: right;&quot; title=&quot;R&amp;eacute;pertoire app/config&quot; src=&quot;http://www.novius-labs.com/data/photo/59.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;&amp;#65279;base_url&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: le base URL de votre site (utilis&amp;eacute; pour g&amp;eacute;n&amp;eacute;rer les URL)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;index_file&lt;/strong&gt;&lt;/span&gt; : &lt;span class=&quot;inline-code&quot;&gt;index.php&lt;/span&gt; si vous n&amp;rsquo;utilisez pas l&amp;rsquo;URL rewriting. &lt;span class=&quot;inline-code&quot;&gt;false&lt;/span&gt; sinon.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;profiling&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: activer ou non le profiler&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;caching&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;: activer ou non le cache&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;errors.notices&lt;/strong&gt;&lt;/span&gt; : faut-il afficher les notices&amp;nbsp;? &lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;language&lt;/strong&gt;&lt;/span&gt; : langue principale de votre application&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;language_fallback&lt;/strong&gt;&lt;/span&gt; : langue de repli&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;locale&lt;/strong&gt;&lt;/span&gt; : la locale PHP (par exemple &lt;span class=&quot;inline-code&quot;&gt;fr_FR&lt;/span&gt; ou &lt;span class=&quot;inline-code&quot;&gt;fr_CA&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;encoding&lt;/strong&gt;&lt;/span&gt; : encodage de votre application&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;default_timezone&lt;/strong&gt;&lt;/span&gt; : par exemple Europe/Paris&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;module_paths&lt;/strong&gt;&lt;/span&gt; : tableau contenant les dossiers o&amp;ugrave; peuvent se situer les modules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En fonction de l&amp;rsquo;environnement (d&amp;eacute;veloppement, test / int&amp;eacute;gration, pr&amp;eacute;-prod / stage, production) des fichiers suppl&amp;eacute;mentaires de configuration peuvent &amp;ecirc;tre charg&amp;eacute;s.&lt;/p&gt;
&lt;p&gt;Par exemple, pour &lt;strong&gt;&lt;span class=&quot;inline-code&quot;&gt;config/config.php&lt;/span&gt;&lt;/strong&gt; si l&amp;rsquo;environnement est &lt;span class=&quot;inline-code&quot;&gt;Fuel::DEVELOPMENT&lt;/span&gt; et que le fichier &lt;span class=&quot;inline-code&quot;&gt;&lt;strong&gt;config/development/config.php&lt;/strong&gt;&lt;/span&gt; existe, il sera &amp;eacute;galement charg&amp;eacute; et les valeurs qu&amp;rsquo;il contient seront fusionn&amp;eacute;es avec celle du fichier de base (avec une priorit&amp;eacute; plus &amp;eacute;lev&amp;eacute;e).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;L'installation est d&amp;eacute;sormais termin&amp;eacute;e. C'est maintenant que tout commence ! &amp;Agrave; tr&amp;egrave;s vite pour la suite de ce tutoriel FuelPHP.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Julian Espérat </dc:creator>
       <pubDate>Tue, 22 Nov 2011 17:31:00 +0100</pubDate>
   </item>
   <item>
       <title>Fiche de lecture &quot;Produire du logiciel libre&quot;</title>
       <link>http://www.novius-labs.com/fiche-lecture-produire-logiciel-libre,32.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_32_vignette.jpg</img>
       <guid>http://www.novius-labs.com/fiche-lecture-produire-logiciel-libre,32.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_32_vignette.jpg&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Le logiciel libre a de quoi dérouter pour les non pratiquants. Même pour un utilisateur convaincu, tout n'est pas très clair. Et le fossé est encore large pour ceux qui veulent se lancer dans la contribution ou mieux, écrire un logiciel libre.&lt;br /&gt;
&lt;br /&gt;
Pour débroussailler les inévitables questions rien de tel qu'un bon livre. Ce billet se propose de faire un compte-rendu de la lecture récente d'un livre sur le logiciel libre : « Produire du logiciel libre » de Karl Fogel.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;Je peux vous le dire par exp&amp;eacute;rience, d&amp;eacute;velopper un logiciel libre, pour une entreprise habitu&amp;eacute; &amp;agrave; la logique propri&amp;eacute;taire, c'est n'est pas aussi simple que de publier des sources. Quelle licence choisir, quel est le mod&amp;egrave;le &amp;eacute;conomique, comment appr&amp;eacute;hender la communaut&amp;eacute;, quels sont nos droits et nos devoirs ? Autant de questions qui sautent imm&amp;eacute;diatement &amp;agrave; la figure. En cherchant &amp;agrave; y r&amp;eacute;pondre, des dizaines d'autres apparaissent, plus pointues, plus pr&amp;eacute;cises mais pas plus &amp;eacute;videntes.&lt;/p&gt;
&lt;p&gt;Heureusement dans le monde du logiciel libre, un des fondements est le partage. De code bien s&amp;ucirc;r, mais pas seulement. Partage d'exp&amp;eacute;riences aussi.&lt;/p&gt;
&lt;p class=&quot;post-title&quot;&gt;&lt;strong&gt;&lt;a title=&quot;http://www.red-bean.com/kfogel/&quot; rel=&quot;nofollow&quot; href=&quot;http://www.red-bean.com/kfogel/&quot;&gt;&lt;br style=&quot;clear: both;&quot; /&gt;Karl Fogel&lt;/a&gt;&lt;/strong&gt; a &amp;eacute;t&amp;eacute;, de 2000 &amp;agrave; 2006, manager de d&amp;eacute;veloppement pour le logiciel &lt;a href=&quot;http://subversion.tigris.org/&quot; target=&quot;_blank&quot;&gt;Subversion&lt;/a&gt; chez &lt;a href=&quot;http://www.collab.net/&quot; target=&quot;_blank&quot;&gt;CollabNet, Inc&lt;/a&gt;. En 2005, il publie un livre&amp;nbsp;&lt;strong&gt;&lt;a href=&quot;http://producingoss.com/&quot; target=&quot;_blank&quot;&gt;&lt;span class=&quot;yellow&quot;&gt;Producing&lt;/span&gt; Open Source           &lt;span class=&quot;yellow&quot;&gt;Software&lt;/span&gt; - How to Run a Successful            &lt;span class=&quot;yellow&quot;&gt;Free Software&lt;/span&gt; Project&lt;/a&gt;&lt;/strong&gt; sous licence libre (&lt;a href=&quot;http://creativecommons.org/licenses/by-sa/3.0/&quot; target=&quot;_blank&quot;&gt;CreativeCommons Attribution-ShareAlike&lt;/a&gt;). En 2010, &lt;strong&gt;&lt;a href=&quot;http://www.framasoft.net/&quot; target=&quot;_blank&quot;&gt;Framasoft&lt;/a&gt;&lt;/strong&gt; lance une traduction et la publie &lt;strong&gt;&lt;a href=&quot;http://www.framablog.org/index.php/post/2011/01/27/produire-du-logiciel-libre-framabook&quot; target=&quot;_blank&quot;&gt;Produire du logiciel libre&lt;/a&gt;&lt;/strong&gt;, toujours sous licence libre, en version papier chez &lt;a class=&quot;offSite&quot; href=&quot;http://www.inlibroveritas.net/&quot;&gt;InLibroVeritas&lt;/a&gt; et en t&amp;eacute;l&amp;eacute;chargement sur &lt;a href=&quot;http://framabook.org/8-produire-du-logiciel-libre&quot; target=&quot;_blank&quot;&gt;Framabook&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;post-title&quot;&gt;J'ai d&amp;eacute;vor&amp;eacute; ce livre !!! Voici un r&amp;eacute;sum&amp;eacute;, chapitre par chapitre et &amp;agrave; base d'extraits pour vous donner l'envie, vous aussi, de le lire.&lt;/p&gt;
&lt;p class=&quot;post-title&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;A qui s'adresse ce livre&amp;nbsp;?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Ce livre s'adresse &lt;strong&gt;aux d&amp;eacute;veloppeurs de logiciels et aux responsables envisageant de lancer un projet Open Source&lt;/strong&gt;, ou l'ayant d&amp;eacute;j&amp;agrave; commenc&amp;eacute;, et qui se demandent que faire ensuite.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nul besoin d'&amp;ecirc;tre programmeur, mais le lecteur devrait conna&amp;icirc;tre les  concepts basiques d'ing&amp;eacute;nierie logicielle tels que code source,  compilateur et correctif.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Une exp&amp;eacute;rience pr&amp;eacute;alable du logiciel Open Source, en tant  qu'utilisateur ou d&amp;eacute;veloppeur, n'est pas n&amp;eacute;cessaire. Ceux qui ont d&amp;eacute;j&amp;agrave;  travaill&amp;eacute; au sein d'un projet de logiciel libre trouveront certaines  parties du livre &amp;eacute;videntes et pourront les passer. &amp;Eacute;tant donn&amp;eacute; le large  &amp;eacute;ventail possible d'exp&amp;eacute;riences des lecteurs, j'ai essay&amp;eacute; de nommer  clairement les diff&amp;eacute;rentes sections et de pr&amp;eacute;ciser celles qui peuvent  &amp;ecirc;tre ignor&amp;eacute;es par les familiers du sujet.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Historique&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Le partage des logiciels est aussi ancien que les logiciels eux  m&amp;ecirc;mes. Aux premiers temps des ordinateurs, les fabricants, sentant que  les b&amp;eacute;n&amp;eacute;fices &amp;eacute;conomiques se trouvaient principalement dans la  production de mat&amp;eacute;riel, ne pr&amp;ecirc;t&amp;egrave;rent gu&amp;egrave;re attention aux logiciels et  leurs atouts financiers&amp;nbsp;&amp;raquo;.&lt;/em&gt; Les utilisateurs avaient acc&amp;egrave;s aux codes  sources, le modifiaient, se l'&amp;eacute;changeaient.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La jungle des normes mat&amp;eacute;rielles a progressivement permis  l'&amp;eacute;mergence de quelques laur&amp;eacute;ats gr&amp;acirc;ce &amp;agrave; une meilleure technologie, une  meilleure strat&amp;eacute;gie voire la combinaison des deux. En m&amp;ecirc;me temps, et pas  enti&amp;egrave;rement par hasard, le d&amp;eacute;veloppement de langages de programmation  dits de &quot;haut niveau&quot; signifiait que l'on pouvait &amp;eacute;crire un programme  une seule fois, dans un langage, et le voir automatiquement traduit  (compil&amp;eacute;) afin de fonctionner sur diff&amp;eacute;rents types d'ordinateurs.&amp;nbsp;&amp;raquo;&lt;/em&gt; La  concurrence se portait alors vers les logiciels et non plus sur le  mat&amp;eacute;riel. C'est l'av&amp;egrave;nement du logiciel propri&amp;eacute;taire ferm&amp;eacute;.&lt;/p&gt;
&lt;p&gt;En 1983, &lt;a href=&quot;http://fr.wikipedia.org/wiki/Richard_Stallman&quot; target=&quot;_blank&quot;&gt;Richard Stallman&lt;/a&gt;, ancien chercheur au &lt;a href=&quot;http://fr.wikipedia.org/wiki/Mit&quot; target=&quot;_blank&quot;&gt;MIT&lt;/a&gt;, lance le projet &lt;a href=&quot;http://www.gnu.org/home.fr.html&quot; target=&quot;_blank&quot;&gt; GNU&lt;/a&gt; et la &lt;a href=&quot;http://www.fsf.org/&quot; target=&quot;_blank&quot;&gt;Free Software Foundation&lt;/a&gt; (FSF). &lt;em&gt;&amp;laquo;&amp;nbsp;En plus de travailler sur le  nouveau syst&amp;egrave;me d'exploitation, Stallman con&amp;ccedil;ut une licence dont les  termes garantissent que son code restera libre &amp;agrave; tout jamais&amp;nbsp;&amp;raquo;&lt;/em&gt;&amp;nbsp;: &lt;a href=&quot;http://www.gnu.org/licenses/gpl.html&quot; target=&quot;_blank&quot;&gt;La GNU  General Public License (GPL) &lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Alors que le monde de l'entreprise pr&amp;ecirc;tait de plus en plus  attention aux logiciels libres, les programmeurs se trouv&amp;egrave;rent  confront&amp;eacute;s &amp;agrave; de nouveaux probl&amp;egrave;mes de repr&amp;eacute;sentation. L'un d'entre eux  &amp;eacute;tait le mot &amp;laquo;&amp;nbsp;free&amp;nbsp;&amp;raquo; lui-m&amp;ecirc;me. Entendant pour la premi&amp;egrave;re fois &amp;laquo;&amp;nbsp;free  software&amp;nbsp;&amp;raquo;, nombre de personnes pensaient, &amp;agrave; tort, que cela signifiait  &amp;laquo;&amp;nbsp;logiciel gratuit&amp;nbsp;&amp;raquo;. S'il est vrai que tous les logiciels libres ne  co&amp;ucirc;tent rien, tous les logiciels gratuits ne sont pas libres.&amp;nbsp;&amp;raquo; ...  &amp;laquo;&amp;nbsp;L'incompr&amp;eacute;hension li&amp;eacute;e au mot free &amp;eacute;tait telle que les programmeurs de  logiciels libres ont fini par cr&amp;eacute;er une formule en r&amp;eacute;ponse&amp;nbsp;: &amp;laquo;&amp;nbsp;C'est  free (libre) comme dans freedom (libert&amp;eacute;), pensez &amp;agrave; free speech (libert&amp;eacute;  de parole), pas &amp;agrave; free beer (bi&amp;egrave;re gratuite)&amp;nbsp;&amp;raquo;.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;En 1998, le terme &amp;laquo;&amp;nbsp;Open Source&amp;nbsp;&amp;raquo; a &amp;eacute;t&amp;eacute; invent&amp;eacute;, en tant  qu'alternative &amp;agrave; &amp;laquo;&amp;nbsp;libre&amp;nbsp;&amp;raquo;, par une coalition de programmeurs devenue  par la suite &lt;a href=&quot;http://www.opensource.org/&quot; target=&quot;_blank&quot;&gt;The Open Source Initiative&lt;/a&gt; (OSI). Pour l'OSI non seulement  le terme &amp;laquo;&amp;nbsp;logiciel libre&amp;nbsp;&amp;raquo; &amp;eacute;tait d&amp;eacute;routant, mais le mot &amp;laquo;&amp;nbsp;libre&amp;nbsp;&amp;raquo;  n'&amp;eacute;tait que le sympt&amp;ocirc;me d'un probl&amp;egrave;me plus g&amp;eacute;n&amp;eacute;ral&amp;nbsp;: le mouvement avait  besoin d'une strat&amp;eacute;gie de commercialisation pour s'adapter au monde de  l'entreprise, et les discours sur les avantages moraux et sociaux du  partage ne p&amp;eacute;n&amp;eacute;treraient pas les conseils d'administration des  entreprises.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;La situation actuelle&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Quand vous dirigez un projet de logiciel libre, vous n'avez pas  besoin de discuter de lourds probl&amp;egrave;mes philosophiques tous les jours.  Les programmeurs n'ont pas &amp;agrave; c&amp;oelig;ur de convertir les autres participants &amp;agrave;  leurs opinions diverses (ceux qui le font se retrouvent rapidement  incapables de travailler sur un projet). Mais vous devez savoir que la  question &quot;libre&quot; contre &quot;Open Source&quot; existe, au moins pour &amp;eacute;viter de  dire des choses inamicales &amp;agrave; certains des participants, mais aussi parce  que comprendre les motivations des d&amp;eacute;veloppeurs est la meilleure  mani&amp;egrave;re, la seule mani&amp;egrave;re en un certain sens, de diriger un projet.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Le logiciel libre est une culture par choix. Pour y naviguer avec  succ&amp;egrave;s, vous devez comprendre pourquoi les gens ont fait le choix d'y  participer en premier lieu. Les mani&amp;egrave;res coercitives ne fonctionnent  pas. Si les gens ne sont pas heureux au c&amp;oelig;ur d'un projet, ils vont  simplement s'en &amp;eacute;carter pour en rejoindre un autre. Le logiciel libre  est remarquable, m&amp;ecirc;me au sein des communaut&amp;eacute;s de volontaires, par la  l&amp;eacute;g&amp;egrave;ret&amp;eacute; de l'investissement. La plupart des gens engag&amp;eacute;s n'ont jamais  vraiment rencontr&amp;eacute;s d'autres participants face &amp;agrave; face, et donnent  simplement un peu de leur temps quand ils en ressentent l'envie. Les  moyens usuels, par lesquels les humains &amp;eacute;tablissent des liens entre eux  et forment des groupes qui durent, sont restreints &amp;agrave; leur plus simple  expression&amp;nbsp;: des mots &amp;eacute;crits transmis par des fils &amp;eacute;lectriques. &amp;Agrave; cause  de cela, la formation d'un groupe soud&amp;eacute; et d&amp;eacute;vou&amp;eacute; peut prendre du temps.  Inversement, un projet peut facilement perdre un volontaire potentiel  dans les cinq premi&amp;egrave;res minutes de pr&amp;eacute;sentation. Si un projet ne fait  pas bonne impression, les nouveaux venus lui donnent rarement une  seconde chance.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;La bri&amp;egrave;vet&amp;eacute;, ou plut&amp;ocirc;t la bri&amp;egrave;vet&amp;eacute; potentielle, des relations est  peut-&amp;ecirc;tre l'obstacle le plus intimidant au commencement d'un nouveau  projet. Qu'est ce qui persuadera tous ces gens de rester group&amp;eacute;s  suffisamment longtemps pour produire quelque chose d'utile&amp;nbsp;? La r&amp;eacute;ponse &amp;agrave;  cette question est suffisamment complexe pour &amp;ecirc;tre le sujet du reste de  ce livre, mais si elle devait &amp;ecirc;tre exprim&amp;eacute;e en une seule phrase, ce  serait&amp;nbsp;:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&quot;Les gens doivent sentir que leur relation &amp;agrave; un projet, et  leur influence sur celui-ci, est directement proportionnelle &amp;agrave; leurs  contributions.&quot;&lt;br /&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Aucune cat&amp;eacute;gorie de d&amp;eacute;veloppeurs, ou de d&amp;eacute;veloppeurs potentiels, ne  devrait se sentir mise &amp;agrave; l'&amp;eacute;cart ou &amp;ecirc;tre discrimin&amp;eacute;e pour des raisons  non-techniques. Les projets port&amp;eacute;s par une soci&amp;eacute;t&amp;eacute; et/ou des  d&amp;eacute;veloppeurs salari&amp;eacute;s doivent y faire particuli&amp;egrave;rement attention, le  chapitre 5 aborde ce sujet plus en d&amp;eacute;tail. Bien s&amp;ucirc;r, cela ne veut pas  dire que, si vous ne b&amp;eacute;n&amp;eacute;ficiez pas du financement d'une soci&amp;eacute;t&amp;eacute;, vous  n'avez &amp;agrave; vous soucier de rien. L'argent n'est que l'un des nombreux  facteurs pouvant influencer le succ&amp;egrave;s d'un projet. Il y a aussi les  questions de choix du langage, de la licence, du processus de  d&amp;eacute;veloppement, du type pr&amp;eacute;cis d'infrastructure &amp;agrave; mettre en place, de la  mani&amp;egrave;re efficace de rendre publique la base du projet et bien plus  encore. Commencer un projet du bon pied est le sujet du prochain  chapitre.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Bien d&amp;eacute;marrer&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La distribution du logiciel libre comporte deux facettes&amp;nbsp;: elle  doit trouver des utilisateurs d'une part et des d&amp;eacute;veloppeurs de l'autre.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ces deux besoins ne sont pas forc&amp;eacute;ment antagonistes m&amp;ecirc;me s'ils  rendent la pr&amp;eacute;sentation initiale du projet plus compliqu&amp;eacute;e. Certaines  informations sont utiles aux deux publics, d'autres le sont uniquement &amp;agrave;  l'un ou &amp;agrave; l'autre. Les deux types d'informations devraient r&amp;eacute;pondre au  principe de pr&amp;eacute;sentation adapt&amp;eacute;e, ce qui signifie que le degr&amp;eacute; de d&amp;eacute;tail  pr&amp;eacute;sent&amp;eacute; &amp;agrave; chacun devrait correspondre directement &amp;agrave; la somme de temps  et d'efforts consentis par le lecteur. Un effort plus important devrait  toujours &amp;ecirc;tre r&amp;eacute;compens&amp;eacute; &amp;agrave; sa juste valeur. Quand le retour sur  investissement n'est pas satisfaisant, les gens peuvent rapidement  perdre la foi et arr&amp;ecirc;ter de s'investir.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Le corollaire en est que les apparences comptent vraiment. Les  programmeurs, en particulier, sont souvent sceptiques &amp;agrave; ce sujet. Leur  amour pour le fond plut&amp;ocirc;t que pour la forme est presque une source de  fiert&amp;eacute; professionnelle. Ce n'est pas un hasard si tant de programmeurs  montrent de l'antipathie envers le marketing et les relations publiques,  ou si les graphistes de m&amp;eacute;tier sont souvent horrifi&amp;eacute;s par ce que les  d&amp;eacute;veloppeurs peuvent produire.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;C'est dommage car il existe des situations - la pr&amp;eacute;sentation d'un  projet en est une - o&amp;ugrave; la forme fait partie du tout. Par exemple, l'une  des premi&amp;egrave;res choses que retient un visiteur &amp;agrave; propos d'un projet est  l'aspect de son site Web. Cette information est absorb&amp;eacute;e avant que le  vrai contenu du site ne soit compris, avant que le texte ne soit lu ou  que le visiteur ne clique sur les liens. M&amp;ecirc;me si cela peut &amp;ecirc;tre injuste,  les gens ne peuvent s'emp&amp;ecirc;cher de se forger une premi&amp;egrave;re impression.  L'apparence du site montre l'application apport&amp;eacute;e &amp;agrave; la pr&amp;eacute;sentation du  projet. Les humains ont des antennes tr&amp;egrave;s sensibles pour d&amp;eacute;tecter le  souci du d&amp;eacute;tail. La plupart d'entre nous peuvent dire en un coup d&amp;rsquo;&amp;oelig;il  si un site Web a &amp;eacute;t&amp;eacute; assembl&amp;eacute; &amp;agrave; la va-vite ou s'il a &amp;eacute;t&amp;eacute; m&amp;ucirc;rement  r&amp;eacute;fl&amp;eacute;chi. C'est la premi&amp;egrave;re information que votre projet montre et  l'impression qu'elle cr&amp;eacute;e p&amp;egrave;sera, par association, sur le reste du  projet.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Chacune des sections suivantes d&amp;eacute;crit un aspect important du  commencement d'un nouveau projet. Elles sont plus ou moins pr&amp;eacute;sent&amp;eacute;es  dans l'ordre d'apparition pour un nouveau visiteur, m&amp;ecirc;me si, bien s&amp;ucirc;r,  votre ordonnancement peut &amp;ecirc;tre diff&amp;eacute;rent. Vous pouvez vous en servir  comme d'une liste de contr&amp;ocirc;le. Quand vous commencez un projet, suivez  cette liste et assurez-vous que chaque point est trait&amp;eacute;, ou au moins que  vous n'aurez pas de probl&amp;egrave;mes quant aux cons&amp;eacute;quences possibles si vous  d&amp;eacute;cidez d'en &amp;eacute;carter un.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Choisissez un bon nom&lt;/strong&gt; : parlant, simple &amp;agrave; m&amp;eacute;moriser, pas de confusion lors de recherche, nom de domaine disponible&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D&amp;eacute;finissez clairement vos objectifs&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Une fois le  site du projet trouv&amp;eacute;, les gens chercheront une description rapide de  sa teneur, votre d&amp;eacute;claration d'intention, afin de pouvoir d&amp;eacute;cider  rapidement (dans les 30 secondes) s'ils souhaitent en savoir plus ou  pas. Cette description devrait avoir une place de choix sur la premi&amp;egrave;re  page, de pr&amp;eacute;f&amp;eacute;rence juste en-dessous du nom du projet.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Indiquez clairement que le projet est libre&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Liste des fonctionnalit&amp;eacute;s&lt;/strong&gt; et pr&amp;eacute;-requis : &lt;em&gt;&amp;laquo;&amp;nbsp;si un aspect n'est  pas encore finalis&amp;eacute;, vous pouvez toujours le lister en ajoutant &amp;agrave; c&amp;ocirc;t&amp;eacute;  &quot;pr&amp;eacute;vu&quot; ou &quot;en cours&quot;&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avancement du d&amp;eacute;veloppement : &lt;/strong&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;[&amp;hellip;] une page  d'avancement, listant les buts du projet &amp;agrave; court terme et ses besoins  [&amp;hellip;] La page peut &amp;eacute;galement fournir un historique des versions pass&amp;eacute;es  avec la liste de leurs fonctionnalit&amp;eacute;s. Ainsi, les visiteurs peuvent se  faire une id&amp;eacute;e de l'&quot;avancement&quot; du projet et sa vitesse de progression  [&amp;hellip;] N'ayez pas peur de para&amp;icirc;tre non-pr&amp;eacute;par&amp;eacute; et ne c&amp;eacute;dez pas &amp;agrave; la  tentation d'exag&amp;eacute;rer la progression du d&amp;eacute;veloppement.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;T&amp;eacute;l&amp;eacute;chargements&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gestion de versions et acc&amp;egrave;s au syst&amp;egrave;me de suivi de bogues&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Les voies de communications&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Fournissez les  adresses des listes de diffusion, des canaux IRC et tout autre forum o&amp;ugrave;  chaque personne impliqu&amp;eacute;e dans le logiciel peut &amp;ecirc;tre jointe. Indiquez  clairement que vous-m&amp;ecirc;me et les autres auteurs du projets sont inscrits  sur ces listes de diffusion afin que les gens puissent voir qu'il existe  des moyens de donner leur avis aux d&amp;eacute;veloppeurs. Votre pr&amp;eacute;sence sur les  listes n'implique pas que vous &amp;ecirc;tes tenu de r&amp;eacute;pondre &amp;agrave; toutes les  questions ou d'int&amp;eacute;grer toutes les suggestions.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Les directives pour d&amp;eacute;veloppeurs&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Si une  personne envisage de contribuer au projet, elle cherchera les directives  pour d&amp;eacute;veloppeurs. Celles-ci ne sont pas vraiment techniques mais  plut&amp;ocirc;t sociales&amp;nbsp;: elles expliquent comment les d&amp;eacute;veloppeurs  interagissent entre eux et avec les utilisateurs, et finalement comment  les choses se d&amp;eacute;roulent.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;La documentation la plus  importante pour les nouveaux utilisateurs concerne les bases&amp;nbsp;: comment  rapidement mettre le logiciel en route, une vue d'ensemble de son  fonctionnement et peut-&amp;ecirc;tre quelques guides pour les t&amp;acirc;ches courantes.  [&amp;hellip;] Entretenir une FAQ [&amp;hellip;] Les bonnes FAQ ne sont pas &amp;eacute;crites, elles se  fa&amp;ccedil;onnent. Ce sont, par d&amp;eacute;finition, des documents r&amp;eacute;actifs, &amp;eacute;voluant  avec le temps en r&amp;eacute;ponse &amp;agrave; l'usage quotidien des utilisateurs du  logiciel [&amp;hellip;] La documentation devrait &amp;ecirc;tre disponible en deux endroits&amp;nbsp;:  en ligne, directement depuis le site Web, et dans la distribution  t&amp;eacute;l&amp;eacute;chargeable du logiciel [&amp;hellip;] La documentation d&amp;eacute;veloppeur est r&amp;eacute;dig&amp;eacute;e  pour aider les programmeurs &amp;agrave; comprendre le code et pouvoir le r&amp;eacute;parer  et le compl&amp;eacute;ter. Elle ne fait pas double emploi avec les directives pour  les d&amp;eacute;veloppeurs dont nous avons parl&amp;eacute; pr&amp;eacute;c&amp;eacute;demment, qui sont plus un  outil social que technique. Ces consignes indiquent aux programmeurs  comment bien collaborer entre eux, la documentation d&amp;eacute;veloppeur leur  indique comment se d&amp;eacute;brouiller avec le code lui-m&amp;ecirc;me.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exemples de r&amp;eacute;alisations et captures d'&amp;eacute;cran&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forges&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Quelques sites proposent un h&amp;eacute;bergement  gratuit ainsi que l'infrastructure pour des projets Open Source [&amp;hellip;] En  utilisant l'un de ces sites vous obtiendrez beaucoup en &amp;eacute;change de rien.  Vous tournez par contre le dos &amp;agrave; un contr&amp;ocirc;le pr&amp;eacute;cis de ce que vous  offrez aux utilisateurs du site.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choisir une licence et l'appliquer&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Une fois la  licence choisie vous devriez la faire appara&amp;icirc;tre sur la premi&amp;egrave;re page du  projet. Vous n'avez pas besoin d'ajouter le texte de la licence &amp;agrave; cet  endroit&amp;nbsp;: pr&amp;eacute;cisez simplement le nom de la licence et cr&amp;eacute;ez un lien vers  le texte complet se trouvant sur une autre page [&amp;hellip;] Vous annoncez ainsi  au public sous quelle licence vous comptez distribuer le projet, mais  ce n'est pas l&amp;eacute;galement suffisant. Pour ceci il faut que le logiciel  contienne cette licence. Habituellement, le texte complet de la licence  se trouve dans un fichier nomm&amp;eacute; copie ou licence, et une petite note en  d&amp;eacute;but de chaque fichier source indique la date du copyright, le  d&amp;eacute;tenteur des droits et l'emplacement du texte complet de la licence.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Donner le ton : &lt;/strong&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Si le projet s'ouvre apr&amp;egrave;s des  ann&amp;eacute;es de d&amp;eacute;veloppement interne, son processus de d&amp;eacute;veloppement s'en  retrouvera modifi&amp;eacute; et vous devrez pr&amp;eacute;parer les d&amp;eacute;veloppeurs d&amp;eacute;j&amp;agrave;  pr&amp;eacute;sents &amp;agrave; ce changement [&amp;hellip;] Les premiers pas sont les plus durs car les  mod&amp;egrave;les et les attentes pour le futur n'ont pas encore &amp;eacute;t&amp;eacute; d&amp;eacute;finis. La  stabilit&amp;eacute; d'un projet n'est pas due &amp;agrave; des r&amp;egrave;gles formelles mais &amp;agrave; une  sagesse collective, difficile &amp;agrave; d&amp;eacute;finir, qui se d&amp;eacute;veloppe avec le temps.  [&amp;hellip;] Une fois le projet ouvert au public, vous et les autres fondateurs  serez tent&amp;eacute;s de r&amp;eacute;gler les probl&amp;egrave;mes d&amp;eacute;licats par des discussions  priv&amp;eacute;es au sein d'un cercle ferm&amp;eacute;. Tous les inconv&amp;eacute;nients des  discussions publiques vous appara&amp;icirc;tront de mani&amp;egrave;re palpable [&amp;hellip;] La  tentation sera effectivement grande de prendre les d&amp;eacute;cisions en petit  comit&amp;eacute; et de les pr&amp;eacute;senter comme des faits accomplis [&amp;hellip;] Ne le faites  pas. Aussi encombrantes et lentes qu'elles puissent &amp;ecirc;tre, les  discussions publiques seront toujours pr&amp;eacute;f&amp;eacute;rables sur le long terme.  Prendre les d&amp;eacute;cisions importantes en priv&amp;eacute; reviendrait &amp;agrave; pulv&amp;eacute;riser du  &quot;repousse-b&amp;eacute;n&amp;eacute;voles&quot; sur le projet [&amp;hellip;] Tuez la vulgarit&amp;eacute; dans l&amp;rsquo;&amp;oelig;uf [&amp;hellip;]  Effectuez une inspection visible du code [&amp;hellip;] Si vous lib&amp;eacute;rez un projet  d&amp;eacute;j&amp;agrave; existant, sur lequel les d&amp;eacute;veloppeurs sont habitu&amp;eacute;s &amp;agrave; travailler  dans un environnement ferm&amp;eacute;, assurez-vous que tout le monde comprenne  qu'un grand changement se profile, essayez de vous mettre &amp;agrave; leur place  pour comprendre leurs sentiments [&amp;hellip;] Le meilleur moyen d'&amp;eacute;viter ceci,  est de tous les pr&amp;eacute;venir de ce qui les attend, expliquez, dites-leur que  l'inconfort du d&amp;eacute;but est parfaitement normal et assurez-les que les  choses iront en s'am&amp;eacute;liorant.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Annoncer&lt;/strong&gt; : &lt;em&gt;&amp;laquo;&amp;nbsp;Une fois que le projet est  pr&amp;eacute;sentable, pas parfait, juste pr&amp;eacute;sentable, vous &amp;ecirc;tes pr&amp;ecirc;t &amp;agrave; l'annoncer  au monde entier. C'est en fait un processus tr&amp;egrave;s simple&amp;nbsp;: allez sur  freshmeat.net &lt;/em&gt;(NDR maintenant &lt;a href=&quot;http://freecode.com/&quot; target=&quot;_blank&quot;&gt;http://freecode.com/&lt;/a&gt;)&lt;em&gt; , cliquez sur &amp;laquo;&amp;nbsp;Submit&amp;nbsp;&amp;raquo; (Soumettre) en haut de la  barre de navigation et remplissez un formulaire pour annoncer  l'existence de votre nouveau projet. C'est sur Freshmeat que tout le  monde se rend pour surveiller les annonces concernant les nouveaux  projets. Vous devrez attirer l'attention de quelques paires d'yeux ici  pour que le bouche &amp;agrave; oreille &amp;agrave; propos de votre projet commence.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Infrastructure technique&lt;/h2&gt;
&lt;p&gt;Ce chapitre liste et d&amp;eacute;crit les infrastructures techniques  n&amp;eacute;cessaires et utiles &amp;agrave; la gestion du projet. &lt;em&gt;&amp;laquo;&amp;nbsp;Prenez garde &amp;agrave; la  tentation d'automatiser les choses qui exigent vraiment une attention  humaine. L'infrastructure technique est importante, mais ce qui fait  fonctionner un projet Open Source, c'est l'attention et l'expression  intelligente de cette attention que les humains impliqu&amp;eacute;s vont d&amp;eacute;ployer.  Le but principal de cette organisation est de fournir &amp;agrave; l'utilisateur  les instruments les plus adapt&amp;eacute;s pour agir.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Site Web&lt;/strong&gt; : &lt;em&gt;&amp;laquo; La vitrine de votre projet aux yeux du  public (centralis&amp;eacute; et &amp;agrave; sens unique). Le site Web peut &amp;eacute;galement servir  d'interface administrative &amp;agrave; d'autres outils du projet. &amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listes de diffusion&lt;/strong&gt; (avec archives publiques) :  &lt;em&gt;&amp;laquo; Traditionnellement le principal moyen de communication, et aussi le plus  actif, au sein du projet. C'est une bonne ressource pour garder trace  des discussions. &amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contr&amp;ocirc;le de version&lt;/strong&gt; : &lt;em&gt;&amp;laquo; Permet aux d&amp;eacute;veloppeurs de  contr&amp;ocirc;ler facilement les changements apport&amp;eacute;s au code, les r&amp;eacute;gressions,  et de g&amp;eacute;rer les branches de d&amp;eacute;veloppements parall&amp;egrave;les. Il permet &amp;agrave;  chacun d'observer les modifications du code. &amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&amp;eacute;f&amp;eacute;rencement de bogues&lt;/strong&gt; : &lt;em&gt;&amp;laquo; Permet aux d&amp;eacute;veloppeurs  d'avoir &amp;agrave; disposition l'historique de leurs travaux, de se coordonner et  de planifier les correctifs. Il Permet &amp;agrave; chacun de conna&amp;icirc;tre le statut  pr&amp;eacute;cis des bogues, et les informations li&amp;eacute;es (par exemple, les  conditions de leur reproductibilit&amp;eacute;). La m&amp;ecirc;me m&amp;eacute;thode peut d'ailleurs  &amp;ecirc;tre employ&amp;eacute;e pour faire le suivi, non seulement des bogues, mais  &amp;eacute;galement des t&amp;acirc;ches, des versions, des nouvelles fonctionnalit&amp;eacute;s, etc. &amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Messagerie instantan&amp;eacute;e ou chat en temps r&amp;eacute;el&lt;/strong&gt; : &lt;em&gt;&amp;laquo; Un  endroit pour les discussions et les &amp;eacute;changes sur un mode de questions -  r&amp;eacute;ponses &amp;eacute;nonc&amp;eacute;es rapidement et simplement. N'est pas toujours archiv&amp;eacute;  compl&amp;egrave;tement. &amp;raquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flux RSS&lt;/strong&gt; pour les annonces, les suivis de bug...&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wiki&lt;/strong&gt; &amp;eacute;ventuellement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Infrastructure sociale et politique&lt;/h2&gt;
&lt;p&gt;Ce chapitre explore la gestion sociale et politique du projet&amp;nbsp;: qui dirige et comment, la m&amp;eacute;ritocratie, la coop&amp;eacute;ration...&lt;/p&gt;
&lt;p&gt;En pr&amp;eacute;alable&amp;nbsp;: &lt;em&gt;&amp;laquo;&amp;nbsp;L'ingr&amp;eacute;dient indispensable qui maintient les  d&amp;eacute;veloppeurs unis autour d'un projet de logiciel libre et les am&amp;egrave;ne &amp;agrave;  faire, si n&amp;eacute;cessaire, des compromis est la &quot;fourchabilit&amp;eacute;&quot; du code,  c'est-&amp;agrave;-dire la possibilit&amp;eacute; offerte &amp;agrave; chacun de prendre une copie du  code source et de l'utiliser pour d&amp;eacute;marrer un projet concurrent, connu  sous le nom de &quot;fork&quot; ou &quot;fourche&quot; en fran&amp;ccedil;ais [&amp;hellip;] Imaginez un roi dont  les sujets pourraient &amp;agrave; tout moment copier le royaume entier et  emm&amp;eacute;nager dans la copie du royaume pour le gouverner comme bon leur  semble. Il est quasi certain que le r&amp;egrave;gne d'un tel roi serait fort  diff&amp;eacute;rent de celui dont les sujets sont contraints de rester sous sa loi  quoi qu'il fasse.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;L'auteur identifie deux types de gestion sociale&amp;nbsp;:&lt;/p&gt;
&lt;h3&gt;Les dictateurs bienveillants&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Bien que &quot;dictateur bienveillant&quot; soit le terme courant pour ce  r&amp;ocirc;le, il vaut mieux l'imaginer comme un &quot;arbitre approuv&amp;eacute; par la  communaut&amp;eacute;&quot; ou un &quot;juge&quot;. G&amp;eacute;n&amp;eacute;ralement, les dictateurs bienveillants ne  prennent pas concr&amp;egrave;tement toutes les d&amp;eacute;cisions, ni m&amp;ecirc;me la plupart. Il  est peu probable qu'une seule personne puisse avoir les comp&amp;eacute;tences  requises dans tous les domaines d'un projet et, de toutes fa&amp;ccedil;ons, les  bons d&amp;eacute;veloppeurs ne s'&amp;eacute;terniseront pas s'ils n'ont pas quelque  influence sur la direction du projet. C'est pourquoi les dictateurs  bienveillants ne dictent g&amp;eacute;n&amp;eacute;ralement pas grand-chose. En revanche, ils  laissent les choses s'&amp;eacute;claircir d'elles-m&amp;ecirc;mes au cours de la discussion  et de l'exp&amp;eacute;rimentation, quand c'est possible. Ils y participent  eux-m&amp;ecirc;mes, mais en tant que simples d&amp;eacute;veloppeurs, s'en remettent souvent  &amp;agrave; un responsable du domaine ayant plus de savoir faire. C'est seulement  quand il appara&amp;icirc;t clairement qu'un consensus ne peut &amp;ecirc;tre trouv&amp;eacute; et que  la majorit&amp;eacute; veut que quelqu'un prenne une d&amp;eacute;cision afin que le  d&amp;eacute;veloppement puisse continuer, qu'il tape du poing sur la table en  disant&amp;nbsp;: &quot;Voil&amp;agrave; ce qu'il faut faire.&quot;&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;La d&amp;eacute;mocratie bas&amp;eacute;e sur le consensus&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;En vieillissant, les projets tendent &amp;agrave; s'&amp;eacute;loigner du mod&amp;egrave;le du  dictateur bienveillant au profit de syst&amp;egrave;mes plus ouvertement  d&amp;eacute;mocratiques.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Quand le consensus n'est pas possible, votez [&amp;hellip;] Le plus difficile,  en ce qui concerne le vote, est de d&amp;eacute;terminer quand il doit avoir lieu  [&amp;hellip;] Un syst&amp;egrave;me de vote c'est bien, mais qui a le droit de vote&amp;nbsp;? C'est  l&amp;agrave; une question potentiellement sensible, car elle oblige le projet &amp;agrave;  distinguer certaines personnes selon leur implication ou leur jugement.  La meilleure solution consiste &amp;agrave; utiliser une distinction existante,  comme l'acc&amp;egrave;s &amp;agrave; la validation (&quot;acc&amp;egrave;s de commit&quot;), et &amp;agrave; y attacher les  privil&amp;egrave;ges du vote&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Arriv&amp;eacute; &amp;agrave; un certain point, le nombre de conventions et d'accords  tacites entourant votre projet risque de devenir si important qu'il  deviendra n&amp;eacute;cessaire de les consigner quelque part&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;L'argent&lt;/h2&gt;
&lt;p&gt;Ce chapitre aborde la question du financement d'un projet de  logiciel libre. Il ne concerne pas uniquement les d&amp;eacute;veloppeurs pay&amp;eacute;s  pour travailler sur des projets de logiciel libre, mais aussi leurs  responsables, qui doivent comprendre les r&amp;egrave;gles sociales r&amp;eacute;gissant le  cadre du d&amp;eacute;veloppement.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Si vous dirigez des programmeurs dans un projet Open Source, faites  en sorte qu'ils participent au projet assez longtemps pour acqu&amp;eacute;rir  l'expertise technique et politique n&amp;eacute;cessaire, deux ans au minimum [&amp;hellip;]  La cr&amp;eacute;dibilit&amp;eacute; acquise ne peut &amp;ecirc;tre transf&amp;eacute;r&amp;eacute;e&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Vos d&amp;eacute;veloppeurs feront leur possible pour s'exprimer, sur les  forums publics de d&amp;eacute;veloppement, en tant que participants individuels  plut&amp;ocirc;t que comme repr&amp;eacute;sentants d'une entreprise monolithique. Ce n'est  pas que la pr&amp;eacute;sence massive d'une entreprise ait une connotation  n&amp;eacute;gative (enfin, c'est possible, mais ce n'est pas le sujet de ce  livre). C'est plut&amp;ocirc;t parce que les projets Open Source ne sont  structurellement &amp;eacute;quip&amp;eacute;s que pour traiter avec des entit&amp;eacute;s  individuelles.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Annoncez les buts de votre organisation en toute transparence, sans  r&amp;eacute;v&amp;eacute;ler de secrets commerciaux. Si vous voulez que le projet incorpore  une certaine fonctionnalit&amp;eacute; parce que, par exemple, vos clients la  r&amp;eacute;clament &amp;agrave; cor et &amp;agrave; cri, annoncez-le clairement sur les listes de  diffusion. Si les clients souhaitent rester anonymes, comme c'est  parfois le cas, demandez-leur au moins si vous pouvez les citer comme  exemples sans les nommer. Les d&amp;eacute;veloppeurs accepteront d'autant mieux  vos propositions qu'ils en conna&amp;icirc;tront les raisons.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Mais la programmation n'est la seule activit&amp;eacute; au sein d'un projet  Open Source, loin s'en faut. Du point de vue des volontaires du projet,  c'est la partie la plus visible et la plus glamour. Ce qui veut  malheureusement dire que les autres activit&amp;eacute;s, comme la documentation ou  les tests formels par exemple, peuvent parfois &amp;ecirc;tre n&amp;eacute;glig&amp;eacute;s, compar&amp;eacute;s &amp;agrave;  l'attention qu'ils re&amp;ccedil;oivent dans les logiciels propri&amp;eacute;taires en tout  cas. Les entreprises arrivent parfois &amp;agrave; compenser cette lacune en  assignant une partie de leur infrastructure de d&amp;eacute;veloppement de logiciel  interne &amp;agrave; des projets Open Source.&amp;nbsp;&amp;raquo; Ce conseil s'applique aux tests,  au c&amp;ocirc;t&amp;eacute; juridique, &amp;agrave; la documentation, l'h&amp;eacute;bergement...&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Afin de conserver la communaut&amp;eacute; de d&amp;eacute;veloppeurs b&amp;eacute;n&amp;eacute;voles de votre  c&amp;ocirc;t&amp;eacute;, il est tr&amp;egrave;s important de ne rien dire qui ne soit v&amp;eacute;rifiable.  Contr&amp;ocirc;lez scrupuleusement toutes vos affirmations et donnez au public  les moyens de les v&amp;eacute;rifier de son c&amp;ocirc;t&amp;eacute;. La v&amp;eacute;rification ind&amp;eacute;pendante et  rapide compose une grande partie du domaine de l'Open Source et cela  s'applique au-del&amp;agrave; du code.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Abstenez-vous de critiquer les logiciels Open Source concurrents.  Vous pouvez tout &amp;agrave; fait exposer des faits n&amp;eacute;gatifs, c'est-&amp;agrave;-dire des  affirmations facilement v&amp;eacute;rifiables, comme c'est souvent le cas dans les  bons tableaux comparatifs. Mais il y a deux raisons pour lesquelles il  vaut mieux &amp;eacute;viter toute l&amp;eacute;g&amp;egrave;ret&amp;eacute; lorsqu'on diffuse des critiques  n&amp;eacute;gatives. Premi&amp;egrave;rement, elles sont susceptibles d'initier une guerre  malsaine qui &amp;eacute;loigne des discussions productives. Et surtout,  deuxi&amp;egrave;mement, il se peut que certains d&amp;eacute;veloppeurs volontaires de votre  projet travaillent &amp;eacute;galement sur le projet concurrent.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Communication&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La capacit&amp;eacute; &amp;agrave; &amp;eacute;crire avec clart&amp;eacute; est peut-&amp;ecirc;tre la qualit&amp;eacute; la plus  importante que l'on puisse avoir dans un environnement Open Source. Sur  le long terme, elle compte davantage que les comp&amp;eacute;tences en  programmation. S'il a des difficult&amp;eacute;s &amp;agrave; communiquer, un programmeur aura  beau &amp;ecirc;tre g&amp;eacute;nial, il ne pourra s'occuper que d'une chose &amp;agrave; la fois, et  il n'est m&amp;ecirc;me pas certain d'obtenir l'attention d&amp;eacute;sir&amp;eacute;e.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;C'est un fait&amp;nbsp;: sur Internet on ne vous conna&amp;icirc;t qu'au travers de vos &amp;eacute;crits ou de ce que l'on &amp;eacute;crit sur vous.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Apr&amp;egrave;s avoir &amp;eacute;crit des milliers de messages, vous observerez  s&amp;ucirc;rement une simplification de votre style. Cela semble &amp;ecirc;tre la norme  dans la plupart des forums techniques, et intrins&amp;egrave;quement, il n'y a rien  de mal &amp;agrave; cela. Un degr&amp;eacute; de simplification inacceptable pour des  interactions sociales habituelles est simplement la norme des hackers de  logiciels libres.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Quand vous participez &amp;agrave; un projet en ligne vous serez tent&amp;eacute; de  r&amp;eacute;pondre &amp;agrave; tout, c'est l'un des pi&amp;egrave;ges classiques. Ne le faites pas.  Tout d'abord, il risque d'y avoir plus de fils de discussions que vous  ne pouvez en suivre, en tout cas une fois que le projet se sera  d&amp;eacute;velopp&amp;eacute;.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Dans une liste de discussion anim&amp;eacute;e, il y a deux imp&amp;eacute;ratifs. Le  premier, &amp;eacute;videmment, consiste &amp;agrave; distinguer ce qui m&amp;eacute;rite votre attention  de ce que vous pouvez ignorer. L'autre consiste &amp;agrave; agir de mani&amp;egrave;re &amp;agrave; ne  pas cr&amp;eacute;er de bruit&amp;nbsp;: vous voulez non seulement que vos propres messages  soient pertinents, mais aussi qu'ils incitent les autres &amp;agrave; en poster  d'aussi pertinents ou bien &amp;agrave; s'abstenir.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La probabilit&amp;eacute; de d&amp;eacute;rive n'est nulle pour aucun fil, mais les  sujets techniques simples sont un terreau tr&amp;egrave;s propice &amp;agrave; l'&amp;eacute;garement.  Apr&amp;egrave;s tout, les sujets techniquement complexes ne seront bien compris  que par une faible proportion de participants, certainement les  d&amp;eacute;veloppeurs les plus exp&amp;eacute;riment&amp;eacute;s ayant d&amp;eacute;j&amp;agrave; pris part &amp;agrave; ce genre de  discussions des milliers de fois, et qui savent comment aboutir &amp;agrave; un  consensus viable pour tous.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;&amp;Eacute;viter les trolls&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Traditionnellement, toutes les communications &amp;eacute;chang&amp;eacute;es dans un  projet Open Source (except&amp;eacute;es parfois les conversations IRC) sont  archiv&amp;eacute;es. Les archives sont publiques, consultables et ont une  stabilit&amp;eacute; r&amp;eacute;f&amp;eacute;rentielle&amp;nbsp;: c'est-&amp;agrave;-dire qu'une information enregistr&amp;eacute;e a  une adresse donn&amp;eacute;e o&amp;ugrave; elle reste pour toujours. Utilisez ces archives  autant que possible et aussi visiblement que possible. M&amp;ecirc;me si vous  connaissez par coeur la r&amp;eacute;ponse &amp;agrave; une question, si vous pensez qu'il y a  dans les archives une r&amp;eacute;f&amp;eacute;rence qui contient la r&amp;eacute;ponse, prenez le  temps d'aller la chercher et de la montrer. Chaque fois que vous faites  ceci publiquement et de mani&amp;egrave;re visible, quelqu'un apprend pour la  premi&amp;egrave;re fois que les archives sont l&amp;agrave; et qu'elles contiennent des  r&amp;eacute;ponses aux questions.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Pas de discussion dans le syst&amp;egrave;me de suivi de bogues&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Faille de s&amp;eacute;curit&amp;eacute;&lt;/h2&gt;
&lt;p&gt;Une partie tr&amp;egrave;s riche en exemples.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La gestion d'une faille de s&amp;eacute;curit&amp;eacute; est diff&amp;eacute;rente de la gestion  des autres rapports de bogue. Dans le logiciel libre, tout faire de  mani&amp;egrave;re ouverte et transparente rel&amp;egrave;ve presque du sacerdoce. Chaque  &amp;eacute;tape d'une correction de bogue standard est visible aux yeux de tous  ceux que cela int&amp;eacute;resse&amp;nbsp;: l'envoi du rapport initial, la discussion qui  s'ensuit et le correctif.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Ne pas parler du bogue en public tant qu'il n'y a pas de correctif  disponible, fournir le correctif exactement au m&amp;ecirc;me moment o&amp;ugrave; vous  annoncez le bogue. Concocter un correctif aussi rapidement que possible,  surtout si c'est quelqu'un d'&amp;eacute;tranger au projet qui a rapport&amp;eacute; le  bogue, parce qu'alors vous savez qu'au moins une personne en dehors du  projet est capable d'exploiter la vuln&amp;eacute;rabilit&amp;eacute;.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Paquets, sorties et d&amp;eacute;veloppement quotidien&lt;/h2&gt;
&lt;p&gt;Un chapitre tr&amp;egrave;s technique sur la num&amp;eacute;rotation des versions,  l'utilisation des branches de publication, le format de livraison, le  changelog, la maintenance de plusieurs versions, la planification des  publications&lt;/p&gt;
&lt;p&gt;Est &amp;eacute;voqu&amp;eacute; &amp;eacute;galement le processus de d&amp;eacute;cision sur ce qui est inclus dans une version.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Encadrer les volontaires&lt;/h2&gt;
&lt;p&gt;Comme son titre l'indique ce chapitre fait le tour de la question de l'encadrement des volontaires&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d&amp;eacute;l&amp;eacute;gation&lt;/li&gt;
&lt;li&gt;f&amp;eacute;licitations et critiques&lt;/li&gt;
&lt;li&gt;partage des taches&lt;/li&gt;
&lt;li&gt;choix des commiters&lt;/li&gt;
&lt;li&gt;responsabilisation (correctif, traduction, documentation, FAQ)&lt;/li&gt;
&lt;li&gt;gestion d'un fork&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Licences, droits d'auteur et brevets&lt;/h2&gt;
&lt;p&gt;Ce chapitre commence par un glossaire des termes suivants&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logiciel libre&lt;/li&gt;
&lt;li&gt;Logiciel Open Source&lt;/li&gt;
&lt;li&gt;Conforme au DFSG - Conforme au contrat social Debian&lt;/li&gt;
&lt;li&gt;Approuv&amp;eacute; OSI - Approuv&amp;eacute; par l'Open Source Initiative&lt;/li&gt;
&lt;li&gt;Propri&amp;eacute;taire, source ferm&amp;eacute;e&lt;/li&gt;
&lt;li&gt;Domaine public&lt;/li&gt;
&lt;li&gt;Copyleft&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il explique ensuite les diff&amp;eacute;rents aspects diff&amp;eacute;renciant les licences&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compatibilit&amp;eacute; avec les licences propri&amp;eacute;taires&lt;/li&gt;
&lt;li&gt;Compatibilit&amp;eacute; avec d'autres licences libres&lt;/li&gt;
&lt;li&gt;L'obligation de cr&amp;eacute;dit&lt;/li&gt;
&lt;li&gt;La protection de marques d&amp;eacute;pos&amp;eacute;es&lt;/li&gt;
&lt;li&gt;La protection de l'&quot;int&amp;eacute;grit&amp;eacute; artistique&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GPL&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Les licences peuvent &amp;ecirc;tre regroup&amp;eacute;es en deux grandes cat&amp;eacute;gories  selon qu'elles sont ou non compatibles avec les licences propri&amp;eacute;taires.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;On distingue donc la Licence Publique G&amp;eacute;n&amp;eacute;rale GNU de toutes les  autres licences. Parce que l'objectif premier des auteurs de la GPL est  la promotion du logiciel libre, ils cr&amp;eacute;&amp;egrave;rent d&amp;eacute;lib&amp;eacute;r&amp;eacute;ment la licence de  fa&amp;ccedil;on &amp;agrave; ce qu'il soit impossible d'int&amp;eacute;grer du code sous GPL au sein de  programmes propri&amp;eacute;taires. En particulier, parmi les conditions de la  GPL, on retrouve ces deux dispositions&amp;nbsp;:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Tout logiciel d&amp;eacute;riv&amp;eacute;, tout logiciel contenant une quantit&amp;eacute; significative de code sous GPL doit &amp;ecirc;tre distribu&amp;eacute; lui-m&amp;ecirc;me sous GPL.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Aucune restriction additionnelle ne peut &amp;ecirc;tre plac&amp;eacute;e sur la redistribution du logiciel original ou d&amp;eacute;riv&amp;eacute;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Avec ces conditions, la GPL parvient &amp;agrave; fabriquer une libert&amp;eacute;  contagieuse. Une fois qu'un programme est licenci&amp;eacute; sous GPL, ses termes  de redistribution sont viraux, ils se transmettent &amp;agrave; tout autre contenu  int&amp;eacute;grant ce code. L'emploi de code sous GPL dans un programme ferm&amp;eacute; est  donc strictement impossible. Cependant, ces m&amp;ecirc;mes clauses rendent aussi  la GPL incompatible avec certaines autres licences libres. C'est  typiquement le cas des licences imposant une exigence suppl&amp;eacute;mentaire  comme, par exemple, une clause de cr&amp;eacute;dit. L'incompatibilit&amp;eacute; avec la GPL  est flagrante puisque cette derni&amp;egrave;re stipule que &quot;Vous ne pouvez pas  imposer de nouvelles restrictions.&quot;. Du point de vue de la Free Software  Foundation, ces effets secondaires sont recherch&amp;eacute;s, ou en tout cas, ils  ne sont pas regrettables. Non seulement la GPL assure la libert&amp;eacute; de  votre logiciel, mais elle en fait aussi un agent poussant les autres  logiciels &amp;agrave; devenir libres.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;La GNU Affero GPL&amp;nbsp;: une version de la GNU GPL pour le code c&amp;ocirc;t&amp;eacute; serveur&lt;/strong&gt;:  En 2007, la Free Software Foundation a publi&amp;eacute; une variante de la GPL  appel&amp;eacute;e GNU Affero GPL*. Elle a &amp;eacute;t&amp;eacute; cr&amp;eacute;&amp;eacute;e pour appliquer les m&amp;ecirc;mes  clauses de partage introduites par la GPL aux entreprises, de plus en  plus nombreuses, qui proposent des services distants, des logiciels qui  fonctionnent sur leurs serveurs, des logiciels avec lesquels les  utilisateurs n'interagissent qu'en ligne et qui ne sont donc jamais  distribu&amp;eacute;s aux utilisateurs sous forme de code source ou d'ex&amp;eacute;cutable.  Un grand nombre de ces services employaient des logiciels sous GPL,  souvent apr&amp;egrave;s y avoir apport&amp;eacute; des modifications, et pourtant ils  n'avaient pas &amp;agrave; partager ces modifications puisque le code n'&amp;eacute;tait pas  distribu&amp;eacute;. La parade de la licence GNU AGPLv3 consiste donc simplement &amp;agrave;  ajouter &amp;agrave; la GPL classique une clause pour les &quot;Interactions &amp;agrave;  distance&quot; indiquant que &quot;&amp;hellip; si vous modifiez le Programme, votre version  modifi&amp;eacute;e doit offrir de mani&amp;egrave;re visible &amp;agrave; tous les utilisateurs  interagissant &amp;agrave; distance gr&amp;acirc;ce &amp;agrave; un r&amp;eacute;seau informatique&amp;hellip; la possibilit&amp;eacute;  de recevoir la Source Correspondante de votre version&amp;hellip; gratuitement,  gr&amp;acirc;ce aux m&amp;eacute;thodes standard ou habituelles de copies de logiciel&quot;. Les  r&amp;egrave;gles &amp;eacute;tablies par la GPL sont ainsi applicables dans le nouveau monde  de la fourniture de services d'applications.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Attribution des droits d'auteur et propri&amp;eacute;t&amp;eacute;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;La gestion des droits d'auteur sur un code libre, fruit du travail  de plusieurs personnes, est une question qu'il vous faudra r&amp;eacute;soudre.  Trois options s'offrent &amp;agrave; vous. La premi&amp;egrave;re consiste &amp;agrave; purement et  simplement ignorer le probl&amp;egrave;me du droit d'auteur (je vous le  d&amp;eacute;conseille). La deuxi&amp;egrave;me est de demander un Accord de Licence du  Participant (ALP) &amp;agrave; chaque personne travaillant sur le projet, accordant  explicitement au projet le droit d'utiliser le code du participant.  C'est en g&amp;eacute;n&amp;eacute;ral suffisant pour la plupart des projets, le point positif  &amp;eacute;tant que dans certaines juridictions ces ALP peuvent &amp;ecirc;tre envoy&amp;eacute;s par  courrier &amp;eacute;lectronique. La troisi&amp;egrave;me possibilit&amp;eacute; est d'obtenir des  participants l'attribution compl&amp;egrave;te des droits d'auteur afin que le  projet (c'est-&amp;agrave;-dire une personne morale, g&amp;eacute;n&amp;eacute;ralement &amp;agrave; but non  lucratif) concentre tous les droits d'auteur. C'est la voie la plus s&amp;ucirc;re  l&amp;eacute;galement, mais aussi la plus contraignante pour les participants,  seuls quelques projets l'empruntent.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Notez que m&amp;ecirc;me si la propri&amp;eacute;t&amp;eacute; intellectuelle est centralis&amp;eacute;e, le  code demeure libre car les licences Open Source ne donnent pas au  d&amp;eacute;tenteur des droits la possibilit&amp;eacute; de rendre r&amp;eacute;troactivement  propri&amp;eacute;taires toutes les copies de ce code. Donc, m&amp;ecirc;me si le projet, en  tant que personne morale, retourne soudainement sa veste, et d&amp;eacute;cide de  distribuer le code sous une licence plus restrictive, cela ne posera pas  de probl&amp;egrave;me &amp;agrave; la communaut&amp;eacute;. Les autres d&amp;eacute;veloppeurs n'auraient qu'&amp;agrave;  initier une fourche bas&amp;eacute;e sur la derni&amp;egrave;re version libre du code, et  continuer comme si de rien n'&amp;eacute;tait. Cette possibilit&amp;eacute; existant, la  plupart des participants coop&amp;egrave;rent lorsqu'on leur demande de signer un  ALP ou une attribution de droit d'auteur.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Quelques exemples d'ALP&amp;nbsp;:&lt;/p&gt;
&lt;p&gt;ALP pour les participants individuels&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;http://apache.org/licenses/icla.txt&quot; rel=&quot;nofollow&quot; href=&quot;http://apache.org/licenses/icla.txt&quot;&gt;http://apache.org/licenses/icla.txt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title=&quot;http://code.google.com/legal/individual-cla-v1.0.html&quot; rel=&quot;nofollow&quot; href=&quot;http://code.google.com/legal/individual-cla-v1.0.html&quot;&gt;http://code.google.com/legal/individual-cla-v1.0.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ALP pour les entreprises participantes&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;http://apache.org/licenses/cla-corporate.txt&quot; rel=&quot;nofollow&quot; href=&quot;http://apache.org/licenses/cla-corporate.txt&quot;&gt;http://apache.org/licenses/cla-corporate.txt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title=&quot;http://code.google.com/legal/corporate-cla-v1.0.html&quot; rel=&quot;nofollow&quot; href=&quot;http://code.google.com/legal/corporate-cla-v1.0.html&quot;&gt;http://code.google.com/legal/corporate-cla-v1.0.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;La double licence&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;laquo;&amp;nbsp;Certains projets tentent de s'auto-financer en adoptant une double  licence, c'est un syst&amp;egrave;me par lequel toute soci&amp;eacute;t&amp;eacute; peut payer le  d&amp;eacute;tenteur des droits d'auteur et obtenir son accord pour utiliser le  code dans un programme propri&amp;eacute;taire, le code restant libre pour les  projets Open Source. Les librairies de code se pr&amp;ecirc;tent &amp;eacute;videmment mieux &amp;agrave;  cette double licence que des applications autonomes. Les termes exacts  varient d'un cas &amp;agrave; l'autre. La licence pour l'aspect libre est la GNU  GPL, puisqu'elle emp&amp;ecirc;che d&amp;eacute;j&amp;agrave; n'importe qui d'ajouter le code prot&amp;eacute;g&amp;eacute;  dans un produit propri&amp;eacute;taire sans l'autorisation du d&amp;eacute;tenteur des  droits, parfois, c'est une licence personnalis&amp;eacute;e ayant les m&amp;ecirc;mes effets.  Ainsi la licence MySQL utilise la licence GNU GPL, on peut aussi  citer comme exemple de licence personnalis&amp;eacute;e le syst&amp;egrave;me de licence de  Sleepycat Software.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Vous vous demandez s&amp;ucirc;rement comment le d&amp;eacute;tenteur des droits peut  proposer une licence propri&amp;eacute;taire contre r&amp;eacute;mun&amp;eacute;ration si les termes de  la GNU GPL stipulent que le code doit &amp;ecirc;tre mis &amp;agrave; disposition sous des  conditions moins restrictives. Les termes de la GPL sont impos&amp;eacute;s par le  d&amp;eacute;tenteur des droits &amp;agrave; tout le monde sauf aux logiciels propri&amp;eacute;taires,  l'auteur est libre de d&amp;eacute;cider de ne pas s'imposer les m&amp;ecirc;mes termes.  Imaginez que le d&amp;eacute;tenteur des droits poss&amp;egrave;de un nombre infini de copies  du logiciel rang&amp;eacute;es dans un seau, &amp;agrave; chaque fois qu'il sort une copie du  seau pour la donner au monde, il peut d&amp;eacute;cider quelle licence appliquer&amp;nbsp;:  GPL, propri&amp;eacute;taire ou autre. Ce n'est pas la GPL ou une quelconque autre  licence Open Source qui lui donne ce droit, ce sont les lois du droit  d'auteur.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Dans le meilleur des cas, la double licence permet ainsi au projet de  logiciel libre de s'assurer une source de revenus stable.  Malheureusement, la dynamique normale d'un projet Open Source peut s'en  retrouver alt&amp;eacute;r&amp;eacute;e. Le probl&amp;egrave;me est que chaque volontaire apportant sa  contribution au code participe maintenant aux deux entit&amp;eacute;s&amp;nbsp;: la fois &amp;agrave;  la version libre et &amp;agrave; la version propri&amp;eacute;taire du code. Contribuer &amp;agrave; la  version libre ne lui posera certainement pas probl&amp;egrave;me, c'est la norme  dans les projets Open Source, mais par contre, participer &amp;agrave; la cr&amp;eacute;ation  de revenus semi-propri&amp;eacute;taires au b&amp;eacute;n&amp;eacute;fice de tiers lui conviendra  peut-&amp;ecirc;tre moins. C'est d'autant plus vrai que, pour une double licence,  les participants doivent c&amp;eacute;der leurs droits au projet par une  d&amp;eacute;claration &amp;eacute;crite. Le projet doit se couvrir au cas o&amp;ugrave; un participant  m&amp;eacute;content pr&amp;eacute;tendrait &amp;agrave; un pourcentage sur les revenus propri&amp;eacute;taires. &amp;Agrave;  partir du moment o&amp;ugrave; les participants signent cette attribution des  droits, ils ne peuvent plus ignorer que leur production enrichira une  autre personne.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tous les volontaires ne se soucieront pas de cela, apr&amp;egrave;s tout, leur  contribution participe &amp;eacute;galement au d&amp;eacute;veloppement de l'&amp;eacute;dition Open  Source, et c'est bien l&amp;agrave; leur int&amp;eacute;r&amp;ecirc;t. N&amp;eacute;anmoins, la double licence est  un exemple o&amp;ugrave; le propri&amp;eacute;taire des droits d'auteur se donne &amp;agrave; lui-m&amp;ecirc;me un  droit particulier que les autres personnes du projet n'ont pas, ce qui  conduira t&amp;ocirc;t ou tard &amp;agrave; des tensions, du moins avec quelques volontaires.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;En pratique, il semble que les entreprises d&amp;eacute;veloppant des logiciels &amp;agrave;  double licence n'ont pas une communaut&amp;eacute; de d&amp;eacute;veloppement vraiment  &amp;eacute;galitaire. Ils profitent de correctifs de bogues mineurs ou de petits  travaux de b&amp;eacute;n&amp;eacute;voles, mais font le gros du travail en interne. Par  exemple, Zack Urlocker, vice pr&amp;eacute;sident du marketing chez MySQL, m'a  confi&amp;eacute; que l'entreprise finit souvent pas employer les volontaires les  plus actifs de toute fa&amp;ccedil;on. Ainsi, le produit en lui m&amp;ecirc;me est Open  Source, sous licence GPL. Son d&amp;eacute;veloppement est plus ou moins contr&amp;ocirc;l&amp;eacute;  par une entreprise, m&amp;ecirc;me si la possibilit&amp;eacute; d'initier une fourche en cas  de profond d&amp;eacute;saccord existe (elle reste extr&amp;ecirc;mement faible cependant).  Je ne sais pas comment cette menace affecte la politique de  l'entreprise, mais en tout cas, MySQL ne semble pas avoir de probl&amp;egrave;me  d'acceptation, que ce soit dans le monde de l'Open Source ou ailleurs.&amp;nbsp;&amp;raquo;&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Tue, 15 Nov 2011 14:51:00 +0100</pubDate>
   </item>
   <item>
       <title>Quel framework choisir ? Nous votons FuelPHP</title>
       <link>http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_29_vignette.png</img>
       <guid>http://www.novius-labs.com/quel-framework-choisir-nous-votons-fuelphp,29.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_29_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Chaque jour amène son lot de nouveaux &lt;i&gt;frameworks&lt;/i&gt;. Comment faire son choix devant cette offre pléthorique ? Voilà la question que nous nous sommes posés au printemps dernier. Après des études et tests, nous avons finalement choisi un petit nouveau, FuelPHP. Cela fait maintenant six mois et nous ne l'avons pas regretté depuis. Voici pourquoi.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper sous FuelPHP&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Choix du framework&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot;&gt;Mise en place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/creation-projet-avec-fuelphp,35.html&quot;&gt;Cr&amp;eacute;ation d'un projet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-4-application-type,38.html&quot;&gt;Application type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-5-cheat-sheet,41.html&quot;&gt;Cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.novius-labs.com/tutoriel-fuelphp-6-orm-gestion-relations,44.html&quot; target=&quot;_blank&quot;&gt;L'ORM : gestion des relations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;FuelPHP est le petit nouveau (la version 1.0 finale est sortie le 31 juillet 2011) qui commence &amp;agrave; se faire un nom dans le monde PHP. Bas&amp;eacute; sur le &lt;a href=&quot;http://net.tutsplus.com/tutorials/php/hvmc-an-introduction-and-application/&quot; target=&quot;_blank&quot;&gt;HMVC&lt;/a&gt;, il ne fonctionne qu&amp;rsquo;&amp;agrave; partir de PHP 5.3 et rassemble des bonnes id&amp;eacute;es de plusieurs autres&amp;nbsp;&lt;em&gt;frameworks&lt;/em&gt; connus&amp;nbsp;:&lt;/p&gt;
&lt;p&gt;Tout comme &lt;strong&gt;CodeIgniter&lt;/strong&gt;, FuelPHP se veut l&amp;eacute;ger et rapide, facile &amp;agrave; apprendre et a peu de d&amp;eacute;pendances niveau serveur.&lt;/p&gt;
&lt;p&gt;Tout comme &lt;strong&gt;Kohana&lt;/strong&gt;, FuelPHP hi&amp;eacute;rarchise l'acc&amp;egrave;s aux fichiers et poss&amp;egrave;de un excellent Query Builder (g&amp;eacute;n&amp;eacute;rateur de requ&amp;ecirc;tes SQL).&lt;/p&gt;
&lt;p&gt;Tout comme &lt;strong&gt;Symfony&lt;/strong&gt;, FuelPHP poss&amp;egrave;de une ligne de commande, un outil de migration, un ORM et un syst&amp;egrave;me de templates.&lt;/p&gt;
&lt;p&gt;On y trouvera &amp;eacute;galement des inspirations de Ruby On Rails ou encore de CakePHP.&lt;/p&gt;
&lt;p&gt;Je ne vais pas vous faire la liste compl&amp;egrave;te des fonctionnalit&amp;eacute;s, mais il faut savoir que malgr&amp;eacute; sa jeunesse, FuelPHP inclut d&amp;eacute;j&amp;agrave; nativement &amp;eacute;norm&amp;eacute;ment d&amp;rsquo;&amp;eacute;l&amp;eacute;ments. Outre tout ce que je viens d&amp;eacute;j&amp;agrave; de citer, on y trouve aussi la gestion de la s&amp;eacute;curit&amp;eacute;, les ACL, tous les moteurs de templates populaires (Mustache, Markdown, Smarty, Twig, Haml, Jade, Dwoo), la validation des formulaires, le REST, le scaffolding, l'envoi de mails, et j&amp;rsquo;en passe&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Simplicit&amp;eacute; de prise en main&lt;/h2&gt;
&lt;p&gt;&amp;Agrave; titre personnel j&amp;rsquo;ai &amp;eacute;t&amp;eacute; tr&amp;egrave;s enchant&amp;eacute; par FuelPHP. Ayant d&amp;eacute;j&amp;agrave; essay&amp;eacute; d&amp;rsquo;autres gros calibre (Zend ou Symfony pour ne pas les citer), le co&amp;ucirc;t &amp;agrave; l&amp;rsquo;entr&amp;eacute;e est relativement important et il faut vraiment s&amp;rsquo;accrocher pour r&amp;eacute;ussir &amp;agrave; faire quelque chose. Au contraire, FuelPHP est vraiment tr&amp;egrave;s facile &amp;agrave; prendre en main et on voit tout de suite le r&amp;eacute;sultat de notre travail. On &amp;eacute;crit peu de code et on comprend ce qui se passe !&lt;/p&gt;
&lt;p&gt;Ok, mon discours est &amp;eacute;vang&amp;eacute;liste, mais l&amp;rsquo;introduction doit bien vous faire envie de lire la suite, non&amp;nbsp;?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Pens&amp;eacute; pour les d&amp;eacute;veloppeurs&lt;/h2&gt;
&lt;p&gt;Tir&amp;eacute; de la documentation officielle : &quot;[...] FuelPHP est n&amp;eacute; de la frustration des d&amp;eacute;veloppeurs avec les &lt;em&gt;frameworks&lt;/em&gt; actuels. [...] Il tire sa fiert&amp;eacute; de sa syntaxe claire.&quot;. Le ton est donn&amp;eacute; !&lt;/p&gt;
&lt;p&gt;Effectivement, FuelPHP est bas&amp;eacute; sur une approche pragmatique : il faut que &amp;ccedil;a soit simple pour le d&amp;eacute;veloppeur. L&amp;rsquo;exemple qui suit (qui fera peut-&amp;ecirc;tre h&amp;eacute;risser les poils sur la t&amp;ecirc;te des puristes) permet de se faire une id&amp;eacute;e :&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;namespaces&lt;/strong&gt; constituent un point central. Le c&amp;oelig;ur de FuelPHP a son propre namespace &lt;span class=&quot;inline-code&quot;&gt;Fuel\Core&lt;/span&gt;. Les classes qu&amp;rsquo;il contient sont automatiquement &lt;em&gt;alias&amp;eacute;es&lt;/em&gt; au namespace global, quand elles sont appel&amp;eacute;es depuis ce dernier et qu&amp;rsquo;elles n&amp;rsquo;y existent pas d&amp;eacute;j&amp;agrave;.&lt;/p&gt;
&lt;p&gt;Concr&amp;egrave;tement c&amp;rsquo;est un jeu d&amp;rsquo;enfant &amp;agrave; l&amp;rsquo;utilisation&amp;nbsp;: pour acc&amp;eacute;der &amp;agrave; la classe &lt;span class=&quot;inline-code&quot;&gt;Controller&lt;/span&gt; fournie par le &lt;em&gt;framework &lt;/em&gt;(et d&amp;eacute;finie dans le namespace &lt;span class=&quot;inline-code&quot;&gt;Fuel\Core&lt;/span&gt;), on acc&amp;egrave;de simplement &amp;agrave; la classe globale &lt;span class=&quot;inline-code&quot;&gt;\Controller&lt;/span&gt;&amp;nbsp;! &lt;strong&gt;C&amp;rsquo;est rapide &amp;agrave; &amp;eacute;crire et tr&amp;egrave;s facile &amp;agrave; retenir !&lt;/strong&gt;&lt;strong&gt; &lt;/strong&gt;Dois-je pr&amp;eacute;ciser que dans Symfony, l&amp;rsquo;acc&amp;egrave;s &amp;agrave; cette m&amp;ecirc;me classe se fait via &lt;span class=&quot;inline-code&quot;&gt;Symfony\Bundle\FrameworkBundle\Controller\Controller&lt;/span&gt;&amp;nbsp;? ;-)&lt;/p&gt;
&lt;p&gt;Et on peut ainsi &lt;strong&gt;&amp;eacute;tendre&lt;/strong&gt; voire m&amp;ecirc;me remplacer n&amp;rsquo;importe quelle classe de &lt;span class=&quot;inline-code&quot;&gt;Fuel\Core&lt;/span&gt; en la d&amp;eacute;finissant dans le namespace global.&lt;/p&gt;
&lt;p&gt;Pour les packages et les modules (nous verrons un peu plus tard ce que c&amp;rsquo;est), la convention est tout aussi enfantine&amp;nbsp;: pas de nom &amp;agrave; rallonge&amp;nbsp;! Chacun utilise un espace de nom simple (&amp;agrave; un seul niveau) correspondant &amp;agrave; son nom.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Alors, &amp;ccedil;a vous donne envie ? &lt;a href=&quot;http://www.novius-labs.com/fuelphp-mise-place-environnement,30.html&quot;&gt;Passons &amp;agrave; l'installation&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Julian Espérat </dc:creator>
       <pubDate>Mon, 14 Nov 2011 14:33:00 +0100</pubDate>
   </item>
   <item>
       <title>Facebook par iA, notre test grandeur nature</title>
       <link>http://www.novius-labs.com/facebook-par-notre-test-grandeur-nature,28.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_28_vignette.png</img>
       <guid>http://www.novius-labs.com/facebook-par-notre-test-grandeur-nature,28.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_28_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Il y a des designs qui marquent. Et par design, j'entends la &lt;a href=&quot;http://www.lukew.com/ff/entry.asp?1418&quot; target=&quot;_blank&quot;&gt;définition de Steve Jobs&lt;/a&gt;. Certains ont été marqués par le presse-agrume de Starck, d'autres par l'iPod ou, plus récemment, par Flipboard.&lt;br /&gt;&lt;br /&gt;
Étonnamment, l'un des designs qui m'a le plus marqué n'a jamais passé le stade du prototype. Enfin, jusqu'il y a peu. Chez Novius, nous l'avons fait passer à l'étape suivante.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Three-pane interface&lt;/h2&gt;
&lt;p&gt;Fin 2006, d&amp;eacute;but 2007, l'agence de design interactif &lt;a href=&quot;http://www.informationarchitects.jp&quot; target=&quot;_blank&quot;&gt;Information Architects&lt;/a&gt; &amp;eacute;tait en contact avec Facebook. L'objectif n'&amp;eacute;tait ni plus ni moins que de reconcevoir, de redesigner le r&amp;eacute;seau social. Le projet n'aboutit pas. Fort heureusement, en mars de l'ann&amp;eacute;e derni&amp;egrave;re, iA d&amp;eacute;cida de publier le travail r&amp;eacute;alis&amp;eacute;. Seul l'habillage graphique fut remis au go&amp;ucirc;t du jour, le concept derri&amp;egrave;re l'interface ne bougea pas :&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.informationarchitects.jp/en/ias-2006-facebook-designs-redesigned/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/47.png&quot; alt=&quot;Facebook par iA&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;C'&amp;eacute;tait la premi&amp;egrave;re foi, &amp;agrave; ma connaissance, qu'une &lt;a href=&quot;http://en.wikipedia.org/wiki/Three-pane_interface&quot; target=&quot;_blank&quot;&gt;three-pane interface&lt;/a&gt; &amp;eacute;tait utilis&amp;eacute;e pour un r&amp;eacute;seau social. Une three-paquoi&amp;nbsp;? L'interface &amp;agrave; trois volets, en bon fran&amp;ccedil;ais, est un standard pour les logiciels de messagerie. M&amp;ecirc;me Google, pourtant farouchement d&amp;eacute;cid&amp;eacute; &amp;agrave; r&amp;eacute;-inventer l'&lt;abbr title=&quot;Exp&amp;eacute;rience utilisateur&quot;&gt;UX&lt;/abbr&gt; email avec Gmail, &lt;a href=&quot;http://www.wired.com/epicenter/2011/08/gmail-three-pane-interface/&quot; target=&quot;_blank&quot;&gt;l'a finalement adopt&amp;eacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le principe de cette interface est le suivant : trois volets li&amp;eacute;s entre eux et organis&amp;eacute;s de mani&amp;egrave;re hi&amp;eacute;rarchique (Dossiers &amp;gt; Emails &amp;gt; D&amp;eacute;tails).&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/49.png&quot; alt=&quot;Three-pane interface pour l'email&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Dans le cas de Facebook par iA, il s'agit de trois volets verticaux, ce qui accentue la hi&amp;eacute;rarchisation du contenu. De gauche &amp;agrave; droite, on trouve ainsi Filtres &amp;gt; Flux d'informations &amp;gt; R&amp;eacute;actions.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://www.novius-labs.com/data/photo/50.png&quot; alt=&quot;Three-pane interface pour Facebook&quot; /&gt;&lt;/p&gt;
&lt;p&gt;D&amp;eacute;tail int&amp;eacute;ressant : l'architecture de l'information est directement visible dans l'&lt;abbr title=&quot;Interface utilisateur&quot;&gt;UI&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/51.png&quot; alt=&quot;Facebook par iA - UI&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Faire converger les communications&lt;/h2&gt;
&lt;p&gt;Quel int&amp;eacute;r&amp;ecirc;t y a-t-il &amp;agrave; utiliser l'interface traditionnelle de l'email pour un r&amp;eacute;seau social ? Oliver Reichenstein de iA cite, entre autres, les avantages suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il y a plus de place pour le flux&lt;/li&gt;
&lt;li&gt;Il y a plus de place pour la discussion&lt;/li&gt;
&lt;li&gt;Les &amp;eacute;l&amp;eacute;ments principaux de navigation sont regroup&amp;eacute;s&lt;/li&gt;
&lt;li&gt;La colonne de droite n'est pas le bazar habituel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mais, ce qui nous a surtout s&amp;eacute;duit au moment de concevoir &lt;a href=&quot;http://www.novius.com/novius-labs/solutions-novius/reso-nova.html&quot; target=&quot;_blank&quot;&gt;R&amp;eacute;so-Nova&lt;/a&gt; (notre solution pour r&amp;eacute;seaux sociaux d'entreprise, RSE, et communaut&amp;eacute;s de marque), c'est le lien fort entre email et r&amp;eacute;seau social, &amp;agrave; l'origine m&amp;ecirc;me de ce design (&quot;Our basic idea, to create an mail-application like interface&quot;, Oliver Reichenstein). Dans le contexte actuel d'infob&amp;eacute;sit&amp;eacute;, l'utilisateur souffre de la multiplication des outils de communication :&amp;nbsp; O&amp;ugrave; est le document ? Dans la &lt;em&gt;knowledge base&lt;/em&gt;. Et l'explication associ&amp;eacute;e ? Je te l'ai envoy&amp;eacute;e par email. Qu'en pense Victor ? Il a r&amp;eacute;pondu sur Facebook.&lt;/p&gt;
&lt;p&gt;Notre objectif avec R&amp;eacute;so-Nova est de faire converger les conversations d'une communaut&amp;eacute; vers un outil central. Or, un premier pas dans cette direction est d'adopter &lt;strong&gt;une interface qui conviennent aux adeptes de l'email comme aux inconditionnels des r&amp;eacute;seaux sociaux&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;De plus, nous cherchons &amp;agrave; doter notre utilisateur d'un outil de &lt;strong&gt;lutte contre l'infob&amp;eacute;sit&amp;eacute;&lt;/strong&gt;. Or, le flux &lt;em&gt;facebookien &lt;/em&gt;est plus long &amp;agrave; parcourir, les r&amp;eacute;actions y &amp;eacute;tant int&amp;eacute;gr&amp;eacute;es. C'est la double peine de l'information non pertinente : non seulement l'utilisateur la voit apparaitre dans son flux, mais elle / il est oblig&amp;eacute;(e) de passer les r&amp;eacute;actions avant d'arriver &amp;agrave; l'information suivante. Dans un flux comme celui imagin&amp;eacute; par iA, on choisit de d&amp;eacute;porter son regard sur la droite pour lire les commentaires. Le parcours rapide du flux est alors possible, de la m&amp;ecirc;me mani&amp;egrave;re qu'on filtre ses emails &amp;agrave; partir de la boite de r&amp;eacute;ception avant d'afficher le d&amp;eacute;tail de certains.&lt;/p&gt;
&lt;p&gt;Enfin, nous avons b&amp;acirc;ti R&amp;eacute;so-Nova autour de groupes th&amp;eacute;matiques. Notre architecture d'information est claire et colle parfaitement &amp;agrave; celle de Facebook par iA : Groupes th&amp;eacute;matiques &amp;gt; Flux &amp;gt; R&amp;eacute;actions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/52.png&quot; alt=&quot;R&amp;eacute;so-Nova UI&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;J'entends des voix qui s'&amp;eacute;l&amp;egrave;vent pour dire : &lt;strong&gt;Twitter a d&amp;eacute;j&amp;agrave; adopt&amp;eacute; ce type d'interface&lt;/strong&gt; ! En effet, la derni&amp;egrave;re interface, dite &lt;a href=&quot;http://techcrunch.com/2010/11/22/facebook-twitter-design/&quot; target=&quot;_blank&quot;&gt;New Twitter, ainsi que Twitter pour iPad ont &amp;eacute;t&amp;eacute; inspir&amp;eacute;s par le travail d'iA&lt;/a&gt;. N&amp;eacute;anmoins, le choix a &amp;eacute;t&amp;eacute; fait sur le web de n'avoir que deux volets (sur iPad, la fine colonne de gauche s'apparente au volet de filtres). De plus, la structure de l'information de Twitter est bien particuli&amp;egrave;re. Les tweets sont limit&amp;eacute;s &amp;agrave; 140 caract&amp;egrave;res et beaucoup de r&amp;eacute;actions prennent la forme de retweets. Ainsi, le volet de droite renvoie souvent des meta-donn&amp;eacute;es (liens vers les utilisateurs cit&amp;eacute;s, utilisateurs ayant retweet&amp;eacute;, etc.), plut&amp;ocirc;t que d'afficher une conversation. A tel point que le formulaire de r&amp;eacute;action n'y est pas pr&amp;eacute;sent. C'est le m&amp;ecirc;me lien que celui pr&amp;eacute;sent sous le tweet et qui ouvre une pop-up.&lt;/p&gt;
&lt;p&gt;Je pense donc que R&amp;eacute;so-Nova est une mise &amp;agrave; l'&amp;eacute;preuve du concept de iA plus fid&amp;egrave;le, mais peut-&amp;ecirc;tre me tromp&amp;eacute;-je ?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;4 mois plus tard&lt;/h2&gt;
&lt;p&gt;Voil&amp;agrave; quatre mois maintenant que la beta de R&amp;eacute;so-Nova motorise notre r&amp;eacute;seau social interne. Pendant cette p&amp;eacute;riode, 1500 contributions ont &amp;eacute;t&amp;eacute; publi&amp;eacute;es g&amp;eacute;n&amp;eacute;rant plus de 4000 commentaires, pour l'entreprise de 35 personnes qu'est Novius. Nous n'avons pas men&amp;eacute; d'&lt;a href=&quot;http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/&quot; target=&quot;_blank&quot;&gt;A/B testing&lt;/a&gt; pour comparer l'efficacit&amp;eacute; de notre flux iA &amp;agrave; un flux &lt;em&gt;facebookien&lt;/em&gt; classique. 35 utilisateurs, c'est bien peu pour une &amp;eacute;tude quantitative. Par contre, notre proximit&amp;eacute; avec les utilisateurs, nos coll&amp;egrave;gues, nous permet de vous livrer cette analyse qualitative.&lt;/p&gt;
&lt;h3&gt;Ce qui a pos&amp;eacute; probl&amp;egrave;me&lt;/h3&gt;
&lt;p&gt;L'aspect le plus probl&amp;eacute;matique de ce design est l'&lt;strong&gt;adoption&lt;/strong&gt;. R&amp;eacute;unir email et r&amp;eacute;seau social dans une m&amp;ecirc;me interface est forc&amp;eacute;ment un compromis, un entre-deux. Ceux &amp;agrave; qui on pr&amp;eacute;sente un r&amp;eacute;seau social d'entreprise s'attende &amp;agrave; trouver un r&amp;eacute;seau social, c'est-&amp;agrave;-dire Facebook. Le lien avec la three-pane interface de l'email est rarement fait, les trois colonnes ressemblant finalement assez peu &amp;agrave; Outlook. L'utilisateur n'est donc pas dans un environnement familier et la prise en main de l'outil s'en ressent.&lt;/p&gt;
&lt;h3&gt;Ce qui a fonctionn&amp;eacute;&lt;/h3&gt;
&lt;p&gt;Ce design est un fantastique &lt;strong&gt;appel &amp;agrave; la r&amp;eacute;action&lt;/strong&gt;. Pour une r&amp;eacute;solution de 900px de haut, on affiche quatre contributions et autant de formulaires pour commenter. R&amp;eacute;agir n'a jamais &amp;eacute;t&amp;eacute; aussi facile et rapide. En octobre, la moyenne de commentaires par utilisateur a &amp;eacute;t&amp;eacute; de 34. Et c'est sans compter les +1, que nous avons voulu tr&amp;egrave;s en avant, &amp;agrave; la mani&amp;egrave;re d'un digg-like.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/53.png&quot; alt=&quot;R&amp;eacute;so-Nova UI&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Points de design&lt;/h3&gt;
&lt;p&gt;Je continue &amp;agrave; m'interroger sur plusieurs points concernant ce design. La gestion du &lt;strong&gt;lu / non lu&lt;/strong&gt;, par exemple, s'est r&amp;eacute;v&amp;eacute;l&amp;eacute;e compliqu&amp;eacute;e. Faut-il un syst&amp;egrave;me &amp;agrave; la Google Reader qui enregistre les lus au-fur-et-&amp;agrave;-mesure du parcours du flux, sans autre action de l'utilisateur que le &lt;em&gt;scroll&lt;/em&gt; ? Ou alors limiter le flux aux seuls sujets &amp;agrave; l'image des emails pour obliger l'utilisateur &amp;agrave; cliquer pour lire ? Pour le moment, nous avons d&amp;eacute;cid&amp;eacute; que seules les actions conscientes de l'utilisateur d&amp;eacute;clenchent le lu : nouveau commentaire, +1, ouverture d'une pi&amp;egrave;ce jointe, visionnage de tous les commentaires, etc. Malgr&amp;eacute; cela, pour de nombreux utilisateurs, les non lus s'accumulent de mani&amp;egrave;re anormale. La solution est-elle dans plus d'automatisation ? C'est &amp;agrave; tester.&lt;/p&gt;
&lt;p&gt;Autre question en suspens, la &lt;strong&gt;hauteur des items du flux&lt;/strong&gt;. Contrairement &amp;agrave; Twitter, les informations publi&amp;eacute;es sur R&amp;eacute;so-Nova sont &amp;agrave; g&amp;eacute;om&amp;eacute;trie variable, du message court semblable &amp;agrave; un tweet &amp;agrave; un long article pareil &amp;agrave; celui que vous &amp;ecirc;tes en train de lire. Pour ne pas emp&amp;ecirc;cher le parcours rapide du flux, la hauteur des items est fixe. C'est donc un r&amp;eacute;sum&amp;eacute;, une information tronqu&amp;eacute;e qui est affich&amp;eacute;e par d&amp;eacute;faut dans le flux. Il faut alors ouvrir l'information pour la voir en entier (c'est la m&amp;ecirc;me action qui affiche tous les commentaires). Or, certains utilisateurs pr&amp;eacute;f&amp;eacute;reraient ne pas avoir tant &amp;agrave; ouvrir et fermer les informations, et que la hauteur r&amp;eacute;fl&amp;egrave;te mieux la longueur. De nouveau, des tests s'imposent.&lt;/p&gt;
&lt;p&gt;Dernier point, l'&lt;strong&gt;ordre des commentaires&lt;/strong&gt;. Quand l'information est r&amp;eacute;sum&amp;eacute;e, les derniers commentaires et le formulaire de r&amp;eacute;action se trouvent directement &amp;agrave; c&amp;ocirc;t&amp;eacute;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/54.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Par contre, d&amp;egrave;s que l'information est ouverte, les voici tout en bas. L'ouverture provoque donc une saute, qui n'est pas des plus ergonomiques.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.novius-labs.com/data/photo/55.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Une solution serait un affichage antichronologique des commentaires, mais le rem&amp;egrave;de ne serait-il pas pire que le mal ?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Vous l'aurez compris, il nous faut encore&lt;strong&gt; it&amp;eacute;rer et it&amp;eacute;rer&lt;/strong&gt; pour affiner ce design. Malgr&amp;eacute; les points bloquants ou sans r&amp;eacute;ponse, je reste un fervent partisan du travail d'iA. Et pas simplement comme designer ; Antoine l'utilisateur a publi&amp;eacute; 200 commentaires le mois dernier.&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Antoine Lefeuvre </dc:creator>
       <pubDate>Thu, 10 Nov 2011 14:18:00 +0100</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : héritage</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-heritage,25.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_25_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-heritage,25.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_25_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;En cinq chapitres, nous avons appris à développer un plugin jQuery UI. J'espère que, comme moi, vous avez été convaincus par l'architecture de widget mise à disposition par le framework jQuery UI. &lt;br /&gt;
Personnellement c'est le chapitre d'aujourd'hui qui m'a le plus attiré dans la démarche jQuery UI : la possibilité d'étendre facilement un widget.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pAV9IL&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Mise en forme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Options et m&amp;eacute;thodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;&amp;Eacute;v&amp;eacute;nements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;H&amp;eacute;ritage&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;Le d&amp;eacute;veloppement Javascript utilise encore trop peu les &lt;a title=&quot;Mathieu Robin : Notion d&amp;rsquo;objets en Javascript&quot; href=&quot;http://nova.li/nyUfEp&quot; target=&quot;_blank&quot;&gt;concepts de d&amp;eacute;veloppement Objet&lt;/a&gt;. L'explosion des sites interactifs, d&amp;eacute;portant la complexit&amp;eacute; du d&amp;eacute;veloppement du serveur vers le navigateur, est assez r&amp;eacute;cente. Le Javascript embarqu&amp;eacute; dans les pages se limitait, il y a encore quelques ann&amp;eacute;es, &amp;agrave; quelques fonctions pour valider les formulaires et deux / trois autres, toutes faites, pour g&amp;eacute;rer du &lt;em&gt;rollover&lt;/em&gt;. Les bonnes pratiques du d&amp;eacute;veloppement Javascript &amp;eacute;mergent petit &amp;agrave; petit, comme pour tout langage informatique. Il faut reconna&amp;icirc;tre &amp;eacute;galement qu'en Javascript &quot;de base&quot;, cr&amp;eacute;er et manipuler des objets est tout sauf intuitif, y compris (et surtout ?) pour un d&amp;eacute;veloppeur ma&amp;icirc;trisant cette technique dans un autre langage.&lt;/p&gt;
&lt;p&gt;Il existe quelques frameworks Javascript facilitant le codage en Objet. Pour parler franchement je n'en ai test&amp;eacute; aucun : quand je code du Javascript en Objet, je r&amp;eacute;invente la roue &amp;agrave; chaque fois. Jusqu'&amp;agrave; ce que je lise &lt;a title=&quot;Understanding jQuery UI widgets: A tutorial&quot; href=&quot;http://nova.li/oeoNcf&quot; target=&quot;_blank&quot;&gt;ce tutorial jQuery dont je vous ai parl&amp;eacute; au premier chapitre&lt;/a&gt;. &amp;Agrave; l'&amp;eacute;poque je cherchais un plugin jQuery du type &quot;popup DHTML&quot;. J'aimais bien le widget &lt;em&gt;Dialog&lt;/em&gt; de jQuery UI mais il lui manquait quelques fonctionnalit&amp;eacute;s dont j'avais absolument besoin. A + B = BAnco, et si j'&amp;eacute;tendais le widget &lt;em&gt;Dialog&lt;/em&gt; pour lui ajouter les fonctionnalit&amp;eacute;s qui me manquaient.&lt;/p&gt;
&lt;p&gt;Au final, mon projet a chang&amp;eacute; de direction et je n'ai pas eu besoin de mon widget &lt;em&gt;Dialog&lt;/em&gt; &amp;eacute;tendu. Mais j'ai gard&amp;eacute; l'habitude de coder mes widgets en jQuery UI et je ne le regrette pas. Aujourd'hui je d&amp;eacute;veloppe une interface type navigateur avec une barre d'onglets bourr&amp;eacute;e de fonctionnalit&amp;eacute;s, et bien entendu je suis parti du widget &lt;em&gt;Tabs&lt;/em&gt; de jQuery UI.&lt;/p&gt;
&lt;h2&gt;Quand est-ce qu'on revoit du code ?&lt;/h2&gt;
&lt;p&gt;Mais assez caus&amp;eacute;. Revenons &amp;agrave; notre exemple. Mettons-nous dans la peau d'un d&amp;eacute;veloppeur qui est pr&amp;ecirc;t &amp;agrave; utiliser notre widget mais qui aimerait bien lui ajouter un petit plus non pr&amp;eacute;vu.&lt;/p&gt;
&lt;p&gt;Notre plugin encapsule un &amp;eacute;l&amp;eacute;ment, lui ajoute un titre et permet d'ouvrir / fermer le bloc. Notre d&amp;eacute;veloppeur aimerait ajouter une petite poign&amp;eacute;e en bas du bloc pour rendre l'ouverture / fermeture plus intuitive.&lt;/p&gt;
&lt;p&gt;Commen&amp;ccedil;ons par &amp;eacute;tendre notre widget initial.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code54&quot; class=&quot;cm-s-default&quot;&gt;// Notre nouveau widget s'appelle blocextend
// Le second paramètre est notre widget bloc initial
// Le troisième paramètre contient le JSON qui va étendre l'objet bloc initial
// Toute fonction ou option non redéfinie sera identique à la version de bloc
$.widget ('demo.blocextend', $.demo.bloc, {
});&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Ajoutons notre petite poign&amp;eacute;e via une red&amp;eacute;finition de la m&amp;eacute;thode &lt;em&gt;_create&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code55&quot; class=&quot;cm-s-default&quot;&gt;_create: function() {
    var self  = this;

    // On appelle la méthode _create du widget bloc initial
    $.demo.bloc.prototype._create.call(this);

    // Notre poignée est un simple lien
    this.uiBlocHandle = $('&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;')
        // La classe ui-bloc-handle nous permettra de positionner correctement la poignée
        .addClass('ui-bloc-handle ui-corner-all ui-state-default')
        // Ajout d'effets visuels d'interaction par les classes CSS d'état de jQuery UI
        .hover(function() {
            self.uiBlocHandle.addClass('ui-state-hover');
        }, function() {
            self.uiBlocHandle.removeClass('ui-state-hover');
        })
        .focus(function() {
            self.uiBlocHandle.addClass('ui-state-focus');
        })
        .blur(function() {
            self.uiBlocHandle.removeClass('ui-state-focus');
        })
        // On ajoute la poignée au container de widget créé dans le bloc initial
        .appendTo(self.uiBlocContainer);

    // Notre poignée contient un SPAN
    this.uiBlocHandleText = $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;')
        // Le SPAN sera une icône en forme de chevron orienté vers le Nord (ui-icon-carat-1-n)
        // Voir la page du themeroller de jQuery UI : http://jqueryui.com/themeroller/
        .addClass('ui-icon ui-icon-carat-1-n')
        // Le texte par défaut de notre poignée
        .text('Ouvrir le bloc')
        // On ajoute le SPAN à la poignée
        .appendTo(self.uiBlocHandle);
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Ajoutons un comportement &amp;agrave; notre poign&amp;eacute;e via la m&amp;eacute;thode &lt;em&gt;_init&lt;/em&gt; &amp;minus; pour comprendre la diff&amp;eacute;rence en &lt;em&gt;_create&lt;/em&gt; et &lt;em&gt;_init&lt;/em&gt;, voir le &lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;chapitre fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code56&quot; class=&quot;cm-s-default&quot;&gt;_init : function() {
    var self = this;

    // On appelle la méthode _init du widget bloc initial
    $.demo.bloc.prototype._init.call(this);

    // On enlève tous les événements click de la poignée
    // En cas de réinitialisation, cela évite d'ajouter un nouvel événement click
    // à notre poignée qui en a déjà potentiellement un
    self.uiBlocHandle.unbind('click');

    if (self.options.togglable) {
        // Notre bloc est fermable
        // On ajoute l'événement click à la poignée qui se contente de déclencher le click sur le titre
        self.uiBlocHandle.click(function(event) {
            self.uiBlocTitle.click();
        }).show(); // On affiche la poignée
    } else {
        // Le bloc n'est pas fermable, on cache la poignée
        self.uiBlocHandle.hide();
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Pour finir modifions les m&amp;eacute;thodes &lt;em&gt;_open&lt;/em&gt; et &lt;em&gt;_close&lt;/em&gt; pour ajuster le look de notre poign&amp;eacute;e en fonction de l'&amp;eacute;tat du bloc.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code57&quot; class=&quot;cm-s-default&quot;&gt;_close: function() {
    var self = this;

    // On appelle la méthode _close du widget bloc initial
    $.demo.bloc.prototype._close.call(this);

    if (self.options.togglable) {
        // Notre bloc est fermable
        // On affiche la poignée qui a été cachée par la méthode _close du bloc initial
        self.uiBlocHandle.show();
    }

    // L'icône de la poignée devient un chevron orienté vers le sud
    // On change aussi le texte
    this.uiBlocHandleText.removeClass('ui-icon-carat-1-n').addClass('ui-icon-carat-1-s').text('Ouvrir le bloc');
},

_open: function() {
    var self = this;

    // On appelle la méthode _open du widget bloc initial
    $.demo.bloc.prototype._open.call(this);

    // L'icône de la poignée devient un chevron orienté vers le nord
    // On change aussi le texte
    this.uiBlocHandleText.removeClass('ui-icon-carat-1-s').addClass('ui-icon-carat-1-n').text('Fermer le bloc');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Un peu de CSS tout de m&amp;ecirc;me&lt;/h2&gt;
&lt;p&gt;Notre poign&amp;eacute;e est pour l'instant un simple lien &amp;agrave; la fin du container de notre bloc. On va la positionner de fa&amp;ccedil;on &amp;agrave; ce qu'elle apparaisse &amp;agrave; cheval sur le bord inf&amp;eacute;rieur du bloc, au milieu de la largeur.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code58&quot; class=&quot;cm-s-default&quot;&gt;/* CSS du widget blocextend pour positionner la poignée */
.ui-bloc {
    /* le bloc est passé en position relative pour pouvoir positionner la poignée à l'intérieur en absolu */
    position: relative;
}
.ui-bloc .ui-bloc-handle {
    /* La poignée est positionnée en absolu par rapport à son container */
    position: absolute;
    right: 50%; /* Elle s'affiche au milieu de la largeur du bloc */
    bottom: 0; /* Elle s'affiche en bas du bloc */
    margin: 0 -10px -10px 0; /* On décale les margin droit et bas de 10 pixels pour l'effet &amp;quot;A cheval&amp;quot; sur la bordure */
}
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Elle est pas belle ma poign&amp;eacute;e ?&lt;/h2&gt;
&lt;p&gt;&lt;iframe width=&quot;100%&quot; height=&quot;300&quot; src=&quot;http://jsfiddle.net/noviuslabs/AyMnA/embedded/result/&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Mon, 05 Sep 2011 14:42:00 +0200</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : fonctionnalités avancées</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-fonctionnalites-avancees,24.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_24_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-fonctionnalites-avancees,24.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_24_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Les 4 premiers chapitres nous ont permis de faire le tour des fonctionnalités principales du framework de création de widgets jQuery UI. Voyons aujourd'hui les fonctionnalités avancées.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pAV9IL&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Mise en forme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Options et m&amp;eacute;thodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;&amp;Eacute;v&amp;eacute;nements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;H&amp;eacute;ritage&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;Le prototype pour widgets jQuery UI impl&amp;eacute;mente par d&amp;eacute;faut plusieurs m&amp;eacute;thodes qui ont vocation &amp;agrave; &amp;ecirc;tre &amp;eacute;tendues. Libre &amp;agrave; vous de les impl&amp;eacute;menter ou non. Nous avons d&amp;eacute;j&amp;agrave; vu la m&amp;eacute;thode &lt;em&gt;_create&lt;/em&gt;, mieux vaut l'impl&amp;eacute;menter sans quoi notre widget ne ferait pas grand chose. Mais il y a aussi &lt;em&gt;_init&lt;/em&gt;, &lt;em&gt;destroy&lt;/em&gt;, &lt;em&gt;enable&lt;/em&gt;, &lt;em&gt;disable&lt;/em&gt; et &lt;em&gt;option&lt;/em&gt; (les descriptions qui suivent sont fortement inspir&amp;eacute;es de la &lt;a href=&quot;http://jqueryui.com/docs/Developer_Guide&quot; target=&quot;_blank&quot;&gt;documentation jQuery UI&lt;/a&gt;) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;_init()&lt;/em&gt;&lt;/strong&gt; : Peut facilement &amp;ecirc;tre confondu avec &lt;em&gt;_create&lt;/em&gt;. &amp;Agrave; la cr&amp;eacute;ation d'un widget, &lt;em&gt;_create&lt;/em&gt; puis &lt;em&gt;_init&lt;/em&gt;&amp;nbsp; sont ex&amp;eacute;cut&amp;eacute;es successivement. Si nous r&amp;eacute;-ex&amp;eacute;cutons notre widget sur un &amp;eacute;l&amp;eacute;ment du DOM d&amp;eacute;j&amp;agrave; instanci&amp;eacute;, seul &lt;em&gt;_init&lt;/em&gt; est appel&amp;eacute;e.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;destroy()&lt;/strong&gt;&lt;/em&gt; : Supprime l'instance du widget qui a &amp;eacute;t&amp;eacute; stock&amp;eacute; en &lt;em&gt;data&lt;/em&gt; dans notre &amp;eacute;l&amp;eacute;ment du DOM. Le retour de l'&amp;eacute;l&amp;eacute;ment du DOM, sur lequel est bas&amp;eacute; notre widget, dans l'&amp;eacute;tat o&amp;ugrave; il &amp;eacute;tait avant la cr&amp;eacute;ation du widget est &amp;agrave; notre charge.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;option(String key[, String value])&lt;/strong&gt; &lt;/em&gt;ou &lt;strong&gt;&lt;em&gt;option(JSON {key1 : value1, key2 : value2} )&lt;/em&gt; &lt;/strong&gt;: Renvoi ou modifie une ou plusieurs options de notre widget.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;enable()&lt;/strong&gt;&lt;/em&gt; : Met l'option &lt;em&gt;disabled&lt;/em&gt; &amp;agrave; &lt;em&gt;false&lt;/em&gt;. Le widget est libre de respecter ou non cette option.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;disable()&lt;/strong&gt;&lt;/em&gt; : Met l'option &lt;em&gt;disabled&lt;/em&gt; &amp;agrave; &lt;em&gt;true&lt;/em&gt;. Le widget est libre de respecter ou non cette option.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rien ne vous oblige &amp;agrave; impl&amp;eacute;menter toutes ces m&amp;eacute;thodes. Si vous le faites ce sont des possibilit&amp;eacute;s suppl&amp;eacute;mentaires que vous offrez aux utilisateurs de votre plugin. Nous imaginons rarement tout ce que les utilisateurs peuvent vouloir faire avec nos cr&amp;eacute;ations. Vous ne voyez peut-&amp;ecirc;tre pas l'utilit&amp;eacute; de pouvoir r&amp;eacute;initialiser, d&amp;eacute;truire ou d&amp;eacute;sactiver votre widget mais il y a de fortes chances pour que certains de vos utilisateurs en aient besoin.&lt;/p&gt;
&lt;p&gt;Voyons maintenant tout cela dans le d&amp;eacute;tail en essayant de trouver des applications fonctionnelles sur notre exemple fil rouge. Je vous laisse juge du r&amp;eacute;sultat dans &lt;a href=&quot;cervo-blog-tutoriaux-recherches,c,4.html?feed=billets#demo&quot;&gt;la d&amp;eacute;mo en fin d'article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;_init&lt;/h2&gt;
&lt;p&gt;Je m'auto-cite : &amp;laquo; &amp;Agrave; la cr&amp;eacute;ation d'un widget &lt;em&gt;_create&lt;/em&gt; puis &lt;em&gt;_init&lt;/em&gt;&amp;nbsp; sont ex&amp;eacute;cut&amp;eacute;es successivement. Si nous r&amp;eacute;-ex&amp;eacute;cutons notre widget sur un &amp;eacute;l&amp;eacute;ment du DOM d&amp;eacute;j&amp;agrave; instanci&amp;eacute;, seul &lt;em&gt;_init&lt;/em&gt; est appel&amp;eacute;e. &amp;raquo;&lt;/p&gt;
&lt;p&gt;Si nous poussons le r&amp;eacute;sonnement, &lt;em&gt;_create&lt;/em&gt; doit contenir la cr&amp;eacute;ation d'&amp;eacute;l&amp;eacute;ments indispensables &amp;agrave; notre widget mais ind&amp;eacute;pendants de toutes options. A l'inverse&lt;em&gt; _init&lt;/em&gt; doit juste se contenter de modifications sur le widget en fonction des options.&lt;/p&gt;
Dans le cadre de notre exemple cela veut donc dire que l'encapsulation de notre &amp;eacute;l&amp;eacute;ment dans un container et que la cr&amp;eacute;ation du bloc pour le titre doivent &amp;ecirc;tre dans &lt;em&gt;_create&lt;/em&gt;. Par contre la modification du contenu du titre et l'application du toggle, qui eux d&amp;eacute;pendent d'options, doivent se faire dans l'&lt;em&gt;_init&lt;/em&gt;.
&lt;p&gt;Reprenons notre code.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code48&quot; class=&quot;cm-s-default&quot;&gt;// La fonction _create est appelée à la construction du widget
_create: function() {
    this.uiBlocContainer = $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;')
        .addClass('ui-bloc ui-widget ui-widget-content ui-corner-all')
        .insertAfter(this.element);

    this.element.addClass('ui-bloc-content').appendTo(this.uiBlocContainer);

    this.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').addClass('ui-bloc-title ui-widget-header ui-corner-top')
        .prependTo(this.uiBlocContainer);

    // On encapsule un SPAN dans le bloc titre pour y écrire le titre et pouvoir le modifier à posteriori
    $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;').appendTo(this.uiBlocTitle);

    // On ajoute un SPAN au bloc titre pour le picto indicateur de l'état d'ouverture / fermeture
    // Mais on le cache au cas où la fonctionnalité serait désactivée
    this.uiBlocTitleToggle = $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;')
        .addClass('ui-bloc-title-toggle ui-icon ui-icon-pin-s')
        .appendTo(this.uiBlocTitle)
        .hide();
},

// La fonction _init est appelée à la construction ET à la réinitialisation du widget
_init : function() {
    var self = this;

    // On renseigne le texte du titre avec la valeur présente dans les options
    self.uiBlocTitle.children('span:first').text(self.options.title);

    // On enlève l'événement click sur le bloc titre
    // En cas de réinitialisation, cela évite d'ajouter un nouvel événement click
    // à notre titre qui en a déjà potentiellement un
    self.uiBlocTitle.unbind('click');

    if (self.options.togglable) {
        // On ajoute l'événement click au bloc titre si le bloc est ouvrable / fermable
        self.uiBlocTitle.click(function(event) {
            self.toggle(event);
            return false;
        }).css('cursor', 'pointer'); // On modifie le curseur au survol du titre

        // On affiche le picto indicateur de l'état d'ouverture / fermeture
        // précédemment crée dans _create
        self.uiBlocTitleToggle.show();

        if (!self.options.opened) {
            // Si le bloc est initialisé avec le paramètre opened à false, on ferme le bloc
            self._close();
        } else {
            // Si le bloc est initialisé avec le paramètre opened à true, on ouvre le bloc
            self._open();
        }
    } else {
        // Le bloc n'est pas togglable
        // On réinitialise le curseur au survol du titre
        self.uiBlocTitle.css('cursor', 'auto');
        // On cache le picto indicateur de l'état d'ouverture / fermeture
        self.uiBlocTitleToggle.hide();
        // On ouvre le bloc
        self._open();
    }
},

toggle : function() {
    var self = this;

    if (!self.options.togglable) {
        return self;
    }

    if (self.options.opened) {
        if (false === this._trigger('beforeClose')) {
            return false;
        }

        self._close();

        this._trigger('close');
    } else {
        if (false === this._trigger('beforeOpen')) {
            return false;
        }

        self._open();

        this._trigger('open');
    }
    self.options.opened = !self.options.opened;

    return self;
},

_close: function() {
    this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');
},

_open: function() {
    this.uiBlocContainer.children().show();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-w').addClass('ui-icon-pin-s');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;A noter que la m&amp;eacute;thode &lt;em&gt;_title&lt;/em&gt; &amp;minus; elle encapsulait la cr&amp;eacute;ation et l'initialisation du bloc titre &amp;minus; a &amp;eacute;t&amp;eacute; purement et simplement d&amp;eacute;truite.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;destroy&lt;/h2&gt;
&lt;p&gt;Maintenant que l'on a bien s&amp;eacute;par&amp;eacute; ce qui &amp;eacute;tait de la cr&amp;eacute;ation et de l'initialisation, la m&amp;eacute;thode &lt;em&gt;destroy&lt;/em&gt; revient &amp;agrave; d&amp;eacute;faire ce que fait &lt;em&gt;_create&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Allons-y gaiement.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code49&quot; class=&quot;cm-s-default&quot;&gt;// La fonction destroy ramène l'élément du DOM, sur lequel est basé notre widget,
// dans l'état où il était avant la création du widget.
// Elle défait ce que _create a fait
destroy: function() {
    // On réaffiche l'élément éventuellement caché
    // On enlève les classes css propres au widget
    // Et on sort l'élément du container
    this.element.show()
        .removeClass('ui-bloc-content')
        .insertBefore(this.uiBlocContainer);

    // On détruit le container
    // Ce qui détruit par ricochet tous les autres éléments créés par notre widget
    this.uiBlocContainer.remove();

    // On appelle la méthode originale du framework
    // Elle supprime l'instance du widget qui a été stocké en data dans l'élément
    $.Widget.prototype.destroy.apply(this);

    return this;
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;option&lt;/h2&gt;
&lt;p&gt;Cette m&amp;eacute;thode sert aussi bien de &lt;em&gt;setter&lt;/em&gt; que de &lt;em&gt;getter&lt;/em&gt;. Elle peut traiter une seule option ou plusieurs en m&amp;ecirc;me temps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;option()&lt;/em&gt;&lt;/strong&gt; : renvoie le JSON des options de notre widget&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;option(String key)&lt;/em&gt;&lt;/strong&gt; : renvoie la valeur de l'option key&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;option(String key, value)&lt;/em&gt;&lt;/strong&gt; : met &amp;agrave; jour l'option key avec la valeur value dans le JSON d'options de notre widget&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;option(JSON &lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;strong&gt; {key1 : value1, key2 : value2})&lt;/strong&gt; : &lt;/em&gt;fusionne le JSON pass&amp;eacute; en param&amp;egrave;tre avec le JSON d'options de notre widget&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;strong&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En mode &lt;em&gt;setter&lt;/em&gt;, l'impl&amp;eacute;mentation par d&amp;eacute;faut de la m&amp;eacute;thode &lt;em&gt;option&lt;/em&gt; dans le framework jQuery UI se contente de modifier la ou les options. Si ces modifications impliquent une mise &amp;agrave; jour de votre widget, c'est &amp;agrave; vous de surcharger &lt;em&gt;option&lt;/em&gt; pour r&amp;eacute;percuter ces modifications &amp;minus; en n'oubliant pas d'appeler la m&amp;eacute;thode originale. En fait, la m&amp;eacute;thode option du framework appelle 2 autres m&amp;eacute;thodes : &lt;em&gt;_setOptions&lt;/em&gt; quand le param&amp;egrave;tre est un JSON et &lt;em&gt;_setOption&lt;/em&gt; quand le premier param&amp;egrave;tre est une cha&amp;icirc;ne. &lt;em&gt;_setOptions&lt;/em&gt; appelle elle-m&amp;ecirc;me &lt;em&gt;_setOption&lt;/em&gt; pour chaque cl&amp;eacute; du JSON. Ce n'est donc pas &lt;em&gt;option&lt;/em&gt; qu'il faut surcharger mais &lt;em&gt;_setOption&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code50&quot; class=&quot;cm-s-default&quot;&gt;// Surcharge de la méthode _setOption qui est appelée par la méthode option
// qui permet de modifier des options de notre widget
_setOption: function(key, value){
    var self = this;

    // On appelle la méthode originale du framework qui modifie le tableau d'options
    $.Widget.prototype._setOption.apply(self, arguments);

    if ($.inArray(key, ['title', 'togglable', 'opened']) != -1) {
        // Si l'option modifiée est une des 3 options title, togglable, opened
        // On appelle la méthode d'initialisation
        self._init();
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Notre ancienne m&amp;eacute;thode &lt;em&gt;title&lt;/em&gt; &amp;minus; elle agissait comme un &lt;em&gt;setter&lt;/em&gt; / &lt;em&gt;getter&lt;/em&gt;&amp;nbsp; sur l'option &lt;em&gt;title&lt;/em&gt; &amp;minus; ne sert plus &amp;agrave; rien : Poubelle !&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;enable / disable&lt;/h2&gt;
&lt;p&gt;Par d&amp;eacute;faut dans le framework jQuery UI, ces deux m&amp;eacute;thodes font deux choses :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elles modifient l'option &lt;em&gt;disabled&lt;/em&gt; respectivement &amp;agrave; &lt;em&gt;false&lt;/em&gt; et &amp;agrave; &lt;em&gt;true&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Elles suppriment / ajoutent une classe css &lt;em&gt;ui-state-disabled&lt;/em&gt; sur notre &amp;eacute;l&amp;eacute;ment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si notre &amp;eacute;l&amp;eacute;ment de base du widget servait lui-m&amp;ecirc;me de container aux &amp;eacute;l&amp;eacute;ments cr&amp;eacute;&amp;eacute;s par le widget, l'aspect visuel du widget pourrait simplement &amp;ecirc;tre chang&amp;eacute; via la classe &lt;em&gt;ui-state-disabled.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Mais avant d'aller plus loin il nous faut d&amp;eacute;finir ce que signifie &quot;d&amp;eacute;sactiv&amp;eacute; notre widget&quot;. Si notre widget &amp;eacute;tait juste un bouton, &amp;ccedil;a pourrait &amp;ecirc;tre un simple grisage et la d&amp;eacute;sactivation du clic. Dans notre cas je propose :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grisage du bloc (titre et contenu)&lt;/li&gt;
&lt;li&gt;D&amp;eacute;sactivation du clic sur le titre dans le cas o&amp;ugrave; le bloc serait &lt;em&gt;togglable&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plut&amp;ocirc;t que de red&amp;eacute;finir &lt;em&gt;enable&lt;/em&gt; et &lt;em&gt;disable&lt;/em&gt;, nous allons utiliser l'option &lt;em&gt;disabled&lt;/em&gt; g&amp;eacute;r&amp;eacute;e nativement. On va donc revenir dans &lt;em&gt;_setOption&lt;/em&gt; pour le grisage.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code51&quot; class=&quot;cm-s-default&quot;&gt;_setOption: function(key, value){
    var self = this;

    $.Widget.prototype._setOption.apply(self, arguments);

    if ($.inArray(key, ['title', 'togglable', 'opened']) != -1) {
        self._init();
    } else if (key === 'disabled') {
        // L'option disabled a été modifiée
        // On ajoute ou supprime, en fonction du cas, la classe ui-state-disabled au container
        // Dans le framework css de jQuery UI, la classe ui-state-disabled grise un élément
        if (value) {
            this.uiBlocContainer.addClass('ui-state-disabled');
        } else {
            this.uiBlocContainer.removeClass('ui-state-disabled');
        }
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Pour la d&amp;eacute;sactivation du clic sur le titre on va se contenter de modifier l'&amp;eacute;v&amp;eacute;nement &lt;em&gt;click&lt;/em&gt; d&amp;eacute;finit dans &lt;em&gt;_init&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code52&quot; class=&quot;cm-s-default&quot;&gt;self.uiBlocTitle.click(function(event) {
    // Si le widget est disabled, il ne se passe rien au click
    if (!self.options.disabled) {
        self.toggle(event);
        return false;
    }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;demo&quot;&gt;&lt;/a&gt;La d&amp;eacute;mo !&lt;/h2&gt;
&lt;p&gt;Comme promis la d&amp;eacute;mo de toutes ces nouvelles fonctionnalit&amp;eacute;s.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;100%&quot; height=&quot;500&quot; src=&quot;http://jsfiddle.net/noviuslabs/5te7q/embedded/result/&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La suite : h&amp;eacute;ritage&lt;/h2&gt;
&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;Sixi&amp;egrave;me chapitre : h&amp;eacute;ritage&lt;/a&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Wed, 24 Aug 2011 10:37:00 +0200</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : événements</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-evenements,22.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_22_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-evenements,22.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_22_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Voici le quatrième chapitre de notre tutoriel. Aujourd'hui, intéressons-nous aux événements.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pAV9IL&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Mise en forme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Options et m&amp;eacute;thodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;Eacute;v&amp;eacute;nements&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;H&amp;eacute;ritage&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;Notre bloc a pris forme. Il est maintenant ouvrable et fermable.&lt;/p&gt;
&lt;p&gt;Imaginons qu'un autre d&amp;eacute;veloppeur utilise le plugin et qu'il veuille d&amp;eacute;clencher une action &amp;agrave; chaque fois que le bloc s'ouvre ou se ferme. En l'&amp;eacute;tat, il serait oblig&amp;eacute; de modifier directement le code source du plugin (dans les m&amp;eacute;thodes &lt;em&gt;_close&lt;/em&gt; et &lt;em&gt;_open&lt;/em&gt;) pour y implanter ses actions. Une option pas franchement intelligente : &amp;agrave; la prochaine mise &amp;agrave; jour du plugin, il faudra qu'il refasse la m&amp;ecirc;me manipulation.&lt;/p&gt;
&lt;p&gt;Facilitons la vie de ce pauvre d&amp;eacute;veloppeur. Deux choix s'offrent &amp;agrave; nous.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Ajoutons des callbacks&lt;/h2&gt;
&lt;p&gt;Les &lt;em&gt;callbacks&lt;/em&gt; sont des fonctions javascript pass&amp;eacute;es en param&amp;egrave;tre, destin&amp;eacute;es &amp;agrave; &amp;ecirc;tre ex&amp;eacute;cut&amp;eacute;es lors d'un &amp;eacute;v&amp;eacute;nement pr&amp;eacute;cis.&lt;/p&gt;
&lt;p&gt;Ajoutons donc deux options &amp;agrave; notre widget.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code39&quot; class=&quot;cm-s-default&quot;&gt;options: {
    title: 'Titre',
    togglable: true,
    opened : true, 
    open : null, // Variable de type callback à déclencher à l'ouverture
    close : null // Variable de type callback à déclencher à la fermeture
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Modifions nos m&amp;eacute;thodes &lt;em&gt;_open&lt;/em&gt; et &lt;em&gt;_close&lt;/em&gt; pour tenir compte de ces options.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code40&quot; class=&quot;cm-s-default&quot;&gt;_close: function() {
    this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');

    // On vérifie si l'option close est bien une fonction
    if ($.isFunction(this.options.close)) {
        // Exécution de la fonction close avec comme contexte l'instance de notre widget (this)
        this.options.close.call(this); 
    }
},

_open: function() {
    this.uiBlocContainer.children().show();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-w').addClass('ui-icon-pin-s');

    // On vérifie si l'option open est bien une fonction
    if ($.isFunction(this.options.open)) {
        // Exécution de la fonction open avec comme contexte l'instance de notre widget (this)
        this.options.open.call(this); 
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Et pour finir, modifions l'initialisation de notre bloc.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code41&quot; class=&quot;cm-s-default&quot;&gt;$('#monbloc1').bloc({
    title: 'Hello bloc 1',
    open: function() {
        // this représente l'instance de notre widget
        alert('Ouverture &amp;gt; ' + this.options.title);
    },
    close: function() {
        alert('Fermeture &amp;gt; ' + this.options.title);
    }
});&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Je ne vous fais pas de d&amp;eacute;mo mais ayez confiance, &amp;ccedil;a marche parfaitement.&lt;/p&gt;
&lt;p&gt;Vous l'avez peut-&amp;ecirc;tre compris, la deuxi&amp;egrave;me solution &amp;agrave; ma pr&amp;eacute;f&amp;eacute;rence.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Ajoutons des triggers&lt;/h2&gt;
&lt;p&gt;Cette solution est l&amp;eacute;g&amp;egrave;rement diff&amp;eacute;rente. Plut&amp;ocirc;t que de d&amp;eacute;clencher les actions de l'int&amp;eacute;rieur du plugin quand les &amp;eacute;v&amp;eacute;nements surviennent, envoyons juste une information &amp;agrave; l'&amp;eacute;l&amp;eacute;ment de notre widget comme quoi l'&amp;eacute;v&amp;eacute;nement a eu lieu. L'avantage est qu'on n'est pas oblig&amp;eacute; de d&amp;eacute;finir l'action &amp;agrave; l'initialisation du widget. On peut le faire &lt;em&gt;a posteriori&lt;/em&gt; aussi simplement que l'on intercepte un &amp;eacute;v&amp;eacute;nement &lt;em&gt;click&lt;/em&gt; sur un bouton &lt;span class=&quot;arial-12-gris&quot;&gt;(&lt;/span&gt;ce n'est pas tout &amp;agrave; fait vrai, c'est &amp;eacute;galement possible avec la premi&amp;egrave;re solution en utilisant le &lt;em&gt;setter $('#monbloc').('open', function() {...});&lt;/em&gt; mais c'est un peu plus compliqu&amp;eacute; et moins intuitif).&lt;/p&gt;
&lt;p&gt;Pour envoyer le signal de l'&amp;eacute;v&amp;eacute;nement, il existe la m&amp;eacute;thode &lt;em&gt;trigger&lt;/em&gt; avec jQuery. Le framework jQuery UI, dans sa grande bont&amp;eacute;, fournit la m&amp;eacute;thode &lt;em&gt;_trigger&lt;/em&gt; qui en fait un peu plus. Que fait-elle de plus ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elle ajoute le nom de votre widget en pr&amp;eacute;fixe du nom de l'&amp;eacute;v&amp;eacute;nement (si vous d&amp;eacute;clenchez un &amp;eacute;v&amp;eacute;nement nomm&amp;eacute; &lt;em&gt;close&lt;/em&gt;, l'&amp;eacute;v&amp;eacute;nement r&amp;eacute;ellement propag&amp;eacute; sera &lt;em&gt;nomduwidgetclose&lt;/em&gt;). Pas de conflit possible avec d'autres &amp;eacute;v&amp;eacute;nements pouvant &amp;ecirc;tre d&amp;eacute;clench&amp;eacute;s par d'autres plugins ou par le framework.&lt;/li&gt;
&lt;li&gt;Elle cr&amp;eacute;e automatiquement un objet &lt;a href=&quot;http://docs.jquery.com/Events/jQuery.Event&quot;&gt;$.Event&lt;/a&gt; si vous n'en fournissez pas un.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;And last but not least&lt;/em&gt;, elle v&amp;eacute;rifie si une option de type &lt;em&gt;callback&lt;/em&gt; du m&amp;ecirc;me nom que votre &amp;eacute;v&amp;eacute;nement &lt;span class=&quot;arial-12-gris&quot;&gt;&amp;ndash; &lt;/span&gt;sans le pr&amp;eacute;fixe du widget &lt;span class=&quot;arial-12-gris&quot;&gt;&amp;ndash;&lt;/span&gt; existe. Si c'est le cas, elle l'ex&amp;eacute;cute avec, comme contexte, l'&amp;eacute;l&amp;eacute;ment de votre widget. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mise en application, toujours dans nos deux m&amp;eacute;thodes&lt;em&gt; _open&lt;/em&gt; et&lt;em&gt; _close&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code42&quot; class=&quot;cm-s-default&quot;&gt;_close: function() {
    this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');

    // Envoi du signal de fermeture
    // _trigger accepte 3 paramètres, les deux derniers étant optionnels : 
    // - le nom de l'événement
    // - l'objet événement
    // - des données additionnelles envoyées aux fonctions interceptant l'événement
    this._trigger('close');
},

_open: function() {
    this.uiBlocContainer.children().show();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-w').addClass('ui-icon-pin-s');

    // Envoi du signal d'ouverture
    this._trigger('open');
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Le code d'initialisation de notre bloc fourni dans la premi&amp;egrave;re solution bas&amp;eacute;e sur les &lt;em&gt;callbacks&lt;/em&gt; fonctionne toujours. Mais, maintenant, on peut aussi faire &amp;ccedil;a :&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code43&quot; class=&quot;cm-s-default&quot;&gt;$('#monbloc1').bloc({
    title: 'Hello bloc 1',
});
$('#monbloc1').bind('blocopen', function() {
    // this représente l'élément sur lequel est appliqué notre widget bloc
    alert('Ouverture &amp;gt; ' + $(this).text());
});
$('#monbloc1').bind('blocclose', function() {
    alert('Fermeture &amp;gt; ' +  $(this).text());
});&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Osons l'interruptionnabilit&amp;eacute; !!&lt;/h2&gt;
&lt;p&gt;Je sens qu'il vous reste encore quelques neurones pour une derni&amp;egrave;re &amp;eacute;tape dans ce chapitre. L'utilisateur de notre plugin peut maintenant &amp;ecirc;tre averti de l'ouverture et de la fermeture du bloc. Bien ! Mais, ce qu'il veut, lui, c'est pouvoir arr&amp;ecirc;ter l'ouverture et la fermeture s'il le d&amp;eacute;cide.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code44&quot; class=&quot;cm-s-default&quot;&gt;_close: function() {
    // Si l'événement beforeClose retourne false, on arrête la fermeture
    if (false === this._trigger('beforeClose')) {
        return;
    }

    this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');

    this._trigger('close');
},

_open: function() {
    // Si l'événement beforeOpen retourne false, on arrête l'ouverture
    if (false === this._trigger('beforeOpen')) {
        return;
    }

    this.uiBlocContainer.children().show();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-w').addClass('ui-icon-pin-s');

    this._trigger('open');
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;MAJ du 17/08/2011&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Petit bug dans l'ajout des &amp;eacute;v&amp;eacute;nements &lt;em&gt;beforeClose&lt;/em&gt; et &lt;em&gt;beforeOpen&lt;/em&gt; : si les &amp;eacute;v&amp;eacute;nements renvoient &lt;em&gt;false&lt;/em&gt;, les m&amp;eacute;thodes &amp;minus; respectivement&amp;nbsp; &lt;em&gt;_close&lt;/em&gt; ou&lt;em&gt; _open&lt;/em&gt; &amp;minus; doivent renvoyer false aussi et non pas simplement &lt;em&gt;return;&lt;/em&gt;. De cette fa&amp;ccedil;on, la m&amp;eacute;thode &lt;em&gt;toggle&lt;/em&gt; peut, elle aussi, tester le retour de &lt;em&gt;_open&lt;/em&gt; et &lt;em&gt;_close&lt;/em&gt; et s'arr&amp;ecirc;ter s'il le faut.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code47&quot; class=&quot;cm-s-default&quot;&gt;toggle : function() {
    var self = this;

    if (!self.options.togglable) {
        return self;
    }

    if (self.options.opened) {
        // Si _close renvoie false, arrêt de l'exécution de toggle 
        if (!self._close()) {
            return;
        }
    } else {
        // Si _open renvoie false, arrêt de l'exécution de toggle 
        if (!self._open()) {
            return;
        }
    }
    self.options.opened = !self.options.opened;

    return self;
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;MAJ du 24/08/2011&lt;/h3&gt;
&lt;p&gt;Le patch du 17 ao&amp;ucirc;t corrigeait un bug mais il en a introduit un autre. Les m&amp;eacute;thodes &lt;em&gt;_open&lt;/em&gt; et&lt;em&gt; _close&lt;/em&gt; ne faisaient aucun &lt;em&gt;return&lt;/em&gt; final, &lt;em&gt;toggle&lt;/em&gt; interpr&amp;eacute;tait &amp;ccedil;a comme un &lt;em&gt;false&lt;/em&gt; et s'arr&amp;ecirc;tait. R&amp;eacute;sultat : le premier &lt;em&gt;toggle&lt;/em&gt; marchait mais les suivants non. Je ne vous fais pas l'affichage du bout de code : ajouter simplement &lt;em&gt;return true;&lt;/em&gt; &amp;agrave; la fin des m&amp;eacute;thodes&lt;em&gt; _open&lt;/em&gt; et &lt;em&gt;_close&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Corrigeons un effet de bord&lt;/h2&gt;
&lt;p&gt;Je ne vous cache rien. En l'&amp;eacute;tat, ce plugin a un petit bug. La m&amp;eacute;thode &lt;em&gt;_close&lt;/em&gt; est appel&amp;eacute;e lors de la fermeture du bloc, mais &amp;eacute;galement &amp;agrave; l'initialisation si l'utilisateur a demand&amp;eacute; &amp;agrave; ce que le bloc soit ferm&amp;eacute; par d&amp;eacute;faut. S'il a, en plus, ajout&amp;eacute; des options &lt;em&gt;close&lt;/em&gt; ou &lt;em&gt;beforeClose&lt;/em&gt; pour ex&amp;eacute;cuter des &lt;em&gt;callbacks&lt;/em&gt; aux d&amp;eacute;clenchements de ces &amp;eacute;v&amp;eacute;nements, ces &lt;em&gt;callbacks&lt;/em&gt; s'ex&amp;eacute;cuteraient aussi &amp;agrave; la cr&amp;eacute;ation du bloc. C'est tout de m&amp;ecirc;me un peu ballot. Corrigeons rapidement &amp;ccedil;a.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code45&quot; class=&quot;cm-s-default&quot;&gt;_create: function() {
    this.uiBlocContainer = $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;')
        .addClass('ui-bloc ui-widget ui-widget-content ui-corner-all')
        .insertAfter(this.element);

    this.element.addClass('ui-bloc-content').appendTo(this.uiBlocContainer);
    this._title();

    if (this.options.togglable &amp;amp;&amp;amp; !this.options.opened) {
        // Le paramètre true est là pour indiquer à la méthode _close qu'elle est appelée par la création du widget
        this._close(true);
    }
},

_close: function(isCreate) {
    // Pas d'événement si c'est la création du widget
    if (!isCreate &amp;amp;&amp;amp; false === this._trigger('beforeClose')) {
        return;
    }

    this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');

    if (!isCreate) {
        this._trigger('close');
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La d&amp;eacute;mo, la d&amp;eacute;mo !!!&lt;/h2&gt;
&lt;p&gt;Juste une pr&amp;eacute;cision avant la d&amp;eacute;mo. Quand vous interceptez vos &amp;eacute;v&amp;eacute;nements, le nom de l'&amp;eacute;v&amp;eacute;nement est en minuscule. Dans notre cas, il faut donc intercepter &lt;em&gt;blocbeforeopen&lt;/em&gt; et non &lt;em&gt;blocbeforeOpen&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;http://jsfiddle.net/noviuslabs/PsTSh/embedded/result/&quot;  width=&quot;100%&quot; height=&quot;500&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La suite : fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/h2&gt;
&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Passons &amp;agrave; la cinqui&amp;egrave;me &amp;eacute;tape, les fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Thu, 11 Aug 2011 16:54:00 +0200</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : options et méthodes</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-options-methodes,21.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_21_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-options-methodes,21.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_21_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Après une pause vacances, reprenons notre tutoriel sur comment développer un plugin jQuery UI. Aujourd'hui, allons un peu plus loin dans les options et les méthodes.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pAV9IL&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Mise en forme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Options et m&amp;eacute;thodes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;&amp;Eacute;v&amp;eacute;nements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;H&amp;eacute;ritage&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;Faisons maintenant &amp;eacute;voluer notre exemple fil rouge. Pour l'instant, on transforme un DIV en un bloc avec titre, dont le &lt;em&gt;look&lt;/em&gt; d&amp;eacute;pend du th&amp;egrave;me jQuery UI choisi. Le but de l'&amp;eacute;tape du jour va &amp;ecirc;tre de pouvoir ouvrir et fermer notre bloc en cliquant sur son titre.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;h2&gt;Ajoutons une m&amp;eacute;thode &lt;em&gt;toggle&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Commen&amp;ccedil;ons par &amp;eacute;crire une m&amp;eacute;thode &lt;em&gt;toggle&lt;/em&gt; qui aura comme but de cacher le contenu du bloc quand il est visible et &lt;a href=&quot;http://fr.wiktionary.org/wiki/vice_versa&quot; target=&quot;_blank&quot;&gt;lyc&amp;eacute;e de Versailles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ajoutons une variable &lt;em&gt;opened&lt;/em&gt; &amp;agrave; nos options.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code26&quot; class=&quot;cm-s-default&quot;&gt;    options: {
        title: 'Titre',
        opened : true // Variable indiquant si le bloc est ouvert 
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Et voici maintenant notre m&amp;eacute;thode &lt;em&gt;toggle &lt;/em&gt;(et ses sous-m&amp;eacute;thodes&lt;em&gt; _open &lt;/em&gt;et&lt;em&gt; _close&lt;/em&gt;)&lt;em&gt;.&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code27&quot; class=&quot;cm-s-default&quot;&gt;    toggle : function() {
        var self = this;
        if (self.options.opened) {
            self._close();
        } else {
            self._open();
        }
        // On inverse la valeur de l'option opened
        self.options.opened = !self.options.opened;

        // On retourne l'instance du plugin pour préserver le chaînage des fonctions
        return self;
    }

    _close: function() {
        // On doit cacher tous les enfants du container sauf le titre
        this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
    },

    _open: function() {
        // On doit afficher tous les enfants du container
        this.uiBlocContainer.children().show();
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Modifions &amp;eacute;galement notre m&amp;eacute;thode&lt;em&gt; _create&lt;/em&gt; pour tenir compte du param&amp;egrave;tre &lt;em&gt;opened.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code38&quot; class=&quot;cm-s-default&quot;&gt;    _create: function() {
        this.uiBlocContainer = $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;')
            .addClass('ui-bloc ui-widget ui-widget-content ui-corner-all')
            .insertAfter(this.element);

        this.element.addClass('ui-bloc-content').appendTo(this.uiBlocContainer);
        this._title();

        if (!this.options.opened) {
            // Si le bloc est initialisé avec le paramètre opened à false, on ferme le bloc
            this._close();
        }
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;En l'&amp;eacute;tat, notre plugin permet d&amp;eacute;j&amp;agrave; d'ouvrir et fermer le bloc via un appel ext&amp;eacute;rieur (la fonction &lt;em&gt;toggle&lt;/em&gt; ne commen&amp;ccedil;ant pas par un &lt;em&gt;underscore&lt;/em&gt;) et d'afficher un bloc ferm&amp;eacute; par d&amp;eacute;faut.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code28&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;button id=&amp;quot;action1&amp;quot;&amp;gt;Changer le titre&amp;lt;/button&amp;gt;
  &amp;lt;button id=&amp;quot;action2&amp;quot;&amp;gt;Alert : le titre&amp;lt;/button&amp;gt;
  &amp;lt;button id=&amp;quot;action3&amp;quot;&amp;gt;Toggle&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
(function($) {
    $(function() {
        $('#monbloc').bloc({
            title : 'Hello world',
            opened : false // Ce bloc est fermé par défaut
        });

        // Le clic sur le bouton Toggle ouvre et ferme alternativement le bloc
        $('#action3').click(function() {
            // On rappelle la fonction bloc sur l'élément
            // avec en paramètre le nom de la fonction interne (toggle)
            $('#monbloc').bloc('toggle');
        }) ;
    });
})(jQuery);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Appellons &lt;em&gt;toggle&lt;/em&gt; quand le titre est cliqu&amp;eacute;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Faisons maintenant en sorte qu'un clic sur la barre de titre d&amp;eacute;clenche ce fameux &lt;em&gt;toggle&lt;/em&gt;. Pour cela, modifions notre m&amp;eacute;thode interne de g&amp;eacute;n&amp;eacute;ration du titre : &lt;em&gt;_title.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code30&quot; class=&quot;cm-s-default&quot;&gt;    _title: function() {
        var self = this;

        this.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').addClass('ui-bloc-title ui-widget-header ui-corner-top')
            .text(this.options.title)
            // On ajoute l'événement clic à notre titre
            .click(function(event) {
                self.toggle(event);
                return false;
            })
            .prependTo(this.uiBlocContainer);
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Pensons &amp;agrave; l'utilisateur&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Ce n'est d&amp;eacute;j&amp;agrave; pas mal, mais, si on se place dans la peau de l'utilisateur, rien ne nous indique que le titre est cliquable. On va donc modifier le curseur au survol du titre et ajouter aussi une ic&amp;ocirc;ne &amp;agrave; droite de la barre de titre indiquant l'&amp;eacute;tat d'ouverture&amp;nbsp;/&amp;nbsp;fermeture du bloc.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code32&quot; class=&quot;cm-s-default&quot;&gt;    _title: function() {
        var self = this;

        self.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').addClass('ui-bloc-title ui-widget-header ui-corner-top')
            .text(self.options.title)
            .click(function(event) {
                self.toggle(event);
                return false;
            })
            .css('cursor', 'pointer') // On modifie le curseur au survol du titre
            .prependTo(this.uiBlocContainer);

        // On ajoute un SPAN à notre titre
        // la classe ui-bloc-title-toggle va nous servir à placer le SPAN à droite dans la barre de titre
        // la classe ui-icon associée à la classe ui-icon-pin-s
        // va transformer notre SPAN en une icône de tête d'épingle orientée sud (vers le bas)
        self.uiBlocTitleToggle = $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;')
            .addClass('ui-bloc-title-toggle ui-icon ui-icon-pin-s')
            .appendTo(self.uiBlocTitle);
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Ajoutons la classe &lt;em&gt;ui-bloc-title-toggle&lt;/em&gt; &amp;agrave; notre CSS.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code33&quot; class=&quot;cm-s-default&quot;&gt;.ui-bloc .ui-bloc-title {
    /* Le titre est en position relative pour permettre au picto toggle (classe ui-bloc-title-toggle)
    d'être positionné en absolu par rapport à lui */
    position: relative;
    margin: 0 0 10px;
    padding: 5px;
}
.ui-bloc .ui-bloc-title-toggle {
    position: absolute;
    right: 0.3em;
    top: 50%;
    width: 16px;
    margin: -8px 0 0 0;
    padding: 1px;
    height: 16px;
    display:block;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Et pour &amp;ecirc;tre au &lt;em&gt;top&lt;/em&gt;, modifions l'ic&amp;ocirc;ne en fonction de l'&amp;eacute;tat d'ouverture / fermeture.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code34&quot; class=&quot;cm-s-default&quot;&gt;    _close: function() {
        this.uiBlocContainer.children().not(this.uiBlocTitle).hide();
        // L'icône de la barre de titre devient une tête d'épingle orientée vers l'ouest (west, donc vers la gauche)
        this.uiBlocTitleToggle.removeClass('ui-icon-pin-s').addClass('ui-icon-pin-w');
    },

    _open: function() {
        this.uiBlocContainer.children().show();
        // L'icône de la barre de titre devient une tête d'épingle orientée vers le sud (vers le bas)
        this.uiBlocTitleToggle.removeClass('ui-icon-pin-w').addClass('ui-icon-pin-s');
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Rendons la fonctionnalit&amp;eacute; &lt;em&gt;toggle&lt;/em&gt; optionnelle&lt;/h2&gt;
&lt;p&gt;Pour finir ce chapitre du tutoriel, nous allons rendre la fonctionnalit&amp;eacute; &lt;em&gt;toggle&lt;/em&gt; optionnelle. Pour cela, ajoutons une nouvelle variable &amp;agrave; nos options.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code35&quot; class=&quot;cm-s-default&quot;&gt;    options: {
        title: 'Titre',
        togglable: true, // Variable indiquant si le bloc est ouvrable / fermable
        opened : true
    },
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Il faut maintenant conditionner tout le code portant sur la fonctionnalit&amp;eacute;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code36&quot; class=&quot;cm-s-default&quot;&gt;    _title: function() {
        var self = this;

        self.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').addClass('ui-bloc-title ui-widget-header ui-corner-top')
            .css('cursor', 'pointer') 
            .prependTo(this.uiBlocContainer);

        $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;').text(self.options.title)
            .appendTo(self.uiBlocTitle);

        if (self.options.togglable) {
            // On ajoute l'événement clic à notre titre si le bloc est ouvrable / fermable
            self.uiBlocTitle.click(function(event) {
                self.toggle(event);
                return false;
            })

            self.uiBlocTitleToggle = $('&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;')
                .addClass('ui-bloc-title-toggle ui-icon ui-icon-pin-s')
                .appendTo(self.uiBlocTitle);
        }
    },

    toggle : function() {
        var self = this;

        //Si le bloc n'est pas ouvrable / fermable, on sort tout de suite
        if (!self.options.togglable) {
            return self;
        }

        if (self.options.opened) {
            self._close();
        } else {
            self._open();
        }
        self.options.opened = !self.options.opened;

        return self;
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La d&amp;eacute;mo de notre plugin en l'&amp;eacute;tat&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;La d&amp;eacute;mo porte maintenant sur deux blocs, un &lt;em&gt;togglable&lt;/em&gt;, l'autre non&lt;em&gt;&amp;nbsp;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;http://jsfiddle.net/noviuslabs/UWa43/embedded/result/&quot;  width=&quot;100%&quot; height=&quot;500&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La suite : les &amp;eacute;v&amp;eacute;nements&lt;/h2&gt;
&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;Passons &amp;agrave; la quatri&amp;egrave;me &amp;eacute;tape, les &amp;eacute;v&amp;eacute;nements&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Thu, 04 Aug 2011 10:34:00 +0200</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : mise en forme</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-mise-forme,19.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_19_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-mise-forme,19.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_19_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Dans la première partie, nous avons vu comment créer un plugin jQuery UI à partir d'un exemple basique. Poursuivons et mettons en forme notre exemple.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br style=&quot;clear: both;&quot; /&gt;
&lt;div class=&quot;summary&quot; style=&quot;float: none;&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pAV9IL&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mise en forme&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Options et m&amp;eacute;thodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;&amp;Eacute;v&amp;eacute;nements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;H&amp;eacute;ritage&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Le framework CSS jQuery UI&lt;/h2&gt;
&lt;p&gt;Le framework CSS jQuery UI fournit une librairie de classes de base &amp;agrave; appliquer &amp;agrave; nos &amp;eacute;l&amp;eacute;ments. Il faut bien s&amp;ucirc;r ensuite ajouter ses propres classes pour affiner le look.&lt;/p&gt;
&lt;p&gt;Voici la &lt;a href=&quot;http://nova.li/pMOIG0&quot; target=&quot;_blank&quot;&gt;page du projet jQuery UI d&amp;eacute;crivant les classes CSS de base&lt;/a&gt;. En compl&amp;eacute;ment, il faut garder sous le coude la &lt;a href=&quot;http://nova.li/nPAQE1&quot; target=&quot;_blank&quot;&gt;page du ThemeRoller&lt;/a&gt;, qui va nous fournir les classes associ&amp;eacute;es &amp;agrave; chaque icone du th&amp;egrave;me.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Retour &amp;agrave; l'exemple&lt;/h2&gt;
&lt;p&gt;Commen&amp;ccedil;ons par ajouter la feuille CSS du th&amp;egrave;me jQuery UI (dans notre cas, c'est le th&amp;egrave;me de base ui-lightness) et quelques CSS sp&amp;eacute;cifiques.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code23&quot; class=&quot;cm-s-default&quot;&gt;
&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;static/js/jquery-ui/css/ui-lightness/jquery-ui-1.8.14.custom.css&amp;quot;&amp;gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
.ui-bloc {
 padding : 0;
 margin-bottom: 10px;
}
.ui-bloc-content {
 margin : 10px;
}
.ui-bloc-title {
 margin : 0 0 10px;
 padding : 5px;
}
&amp;lt;/style&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Revenons &amp;agrave; notre m&amp;eacute;thode _create de cr&amp;eacute;ation du widget&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code24&quot; class=&quot;cm-s-default&quot;&gt;_create: function() {
    // On crée un container pour notre nouvel élément d'UI
    // On lui ajoute la classe ui-widget qui doit être ajoutée à tout container de widget
    // On lui ajoute également la classe ui-widget-content qui doit être appliquée  à tout container de contenu de widget
    // La classe ui-corner-all arrondit les 4 angles de notre bloc
    this.uiBlocContainer = $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;').addClass('ui-bloc ui-widget ui-widget-content ui-corner-all').insertAfter(this.element);

    // On encapsule notre élément initial dans notre nouveau container
    this.element.addClass('ui-bloc-content').appendTo(this.uiBlocContainer);
    this._title() ;
},&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Dans notre m&amp;eacute;thode _title, am&amp;eacute;liorons le look du titre.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code25&quot; class=&quot;cm-s-default&quot;&gt;_title: function() {
    // On ajoute la classe ui-widget-header qui doit être ajoutée à tout élément titre de widget
    // La classe ui-corner-top arrondit les 2 angles suppérieurs de notre bloc titre
    // L'élément uiBlocTitle est ajouté au container et non plus à notre élément de base
    this.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').addClass('ui-bloc-title ui-widget-header ui-corner-top').text(this.options.title).prependTo(this.uiBlocContainer);
},&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2&gt;Observons le r&amp;eacute;sultat&lt;/h2&gt;
&lt;p&gt;&lt;iframe src=&quot;http://jsfiddle.net/noviuslabs/EQQRe/embedded/result/&quot; width=&quot;100%&quot; height=&quot;500&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La suite : options et m&amp;eacute;thodes&lt;/h2&gt;
&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Passons &amp;agrave; la troisi&amp;egrave;me &amp;eacute;tape, options et m&amp;eacute;thodes&lt;/a&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Tue, 12 Jul 2011 14:39:00 +0200</pubDate>
   </item>
   <item>
       <title>Développer un plugin jQuery UI : introduction</title>
       <link>http://www.novius-labs.com/developper-plugin-jquery-introduction,18.html</link>
       <img>http://www.novius-labs.com/data/classes/blog/blog_18_vignette.png</img>
       <guid>http://www.novius-labs.com/developper-plugin-jquery-introduction,18.html</guid>
       <description>&lt;img src=&quot;http://www.novius-labs.com/data/classes/blog/blog_18_vignette.png&quot; vspace=&quot;5&quot; /&gt;&lt;p&gt;&lt;b&gt;Tout utilisateur de jQuery connaît la librairie jQuery UI fournie par l'équipe officielle de jQuery. &lt;br /&gt;
&lt;br /&gt;
jQuery UI fourni des effets supplémentaires, des plugins basses couches d'interactions et des widgets packagés prêts à l'emploi. Tous les plugins jQuery UI sont construits de la même façon et basés sur un système de thèmes CSS complètement personnalisables. Il y a même à disposition une application de ThemeRoller pour construire son propre thème et un widget Theme Switcher pour pouvoir modifier son thème à la volée.&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;div class=&quot;summary&quot;&gt;
&lt;p&gt;Sommaire du tutoriel&lt;br /&gt; &lt;strong&gt;D&amp;eacute;velopper un plugin jQuery UI&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Mise en forme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/qnovwO&quot;&gt;Options et m&amp;eacute;thodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/r4LBrV&quot;&gt;&amp;Eacute;v&amp;eacute;nements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/n48OEx&quot;&gt;Fonctionnalit&amp;eacute;s avanc&amp;eacute;es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nova.li/pmoBmz&quot;&gt;H&amp;eacute;ritage&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;J'utilise r&amp;eacute;guli&amp;egrave;rement quelques-uns des widgets officiels et j'ai utilis&amp;eacute; les plugins d'interactions pour d&amp;eacute;velopper quelques plugins sp&amp;eacute;cifiques. Mais, je ne m'&amp;eacute;tais jamais attard&amp;eacute; sur l'API sous-jacente &amp;agrave; jQuery UI. C'est un tort.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;Dans le cadre d'un des projets de Novius Labs, j'avais besoin d'un ensemble d'UI. J'ai commenc&amp;eacute; par faire un inventaire de tous les plugins jQuery existants qui pouvait me servir. Mais, au final, j'avais une liste de plugins sans coh&amp;eacute;rence et j'aurais &amp;eacute;t&amp;eacute; oblig&amp;eacute; pour chacun de mettre les mains dans le cambouis, pour leur faire faire ce que je voulais.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;Parmi cette liste de plugins, il y avait plusieurs widgets jQuery UI. J'ai donc creus&amp;eacute; un peu de ce c&amp;ocirc;t&amp;eacute; l&amp;agrave;. Je pris le temps de lire la page &lt;a href=&quot;http://nova.li/nK2mH6&quot; target=&quot;_blank&quot;&gt;jQuery UI API Developer Guide&lt;/a&gt;, qui m'a renvoy&amp;eacute; vers ce tutorial &lt;a href=&quot;http://nova.li/oeoNcf&quot; target=&quot;_blank&quot;&gt;Understanding jQuery UI widgets: A tutorial&lt;/a&gt;. J'ai alors d&amp;eacute;couvert le framework qui me manquait pour d&amp;eacute;velopper mes plugins.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;Jusqu'&amp;agrave; pr&amp;eacute;sent, &amp;agrave; chaque fois que je devais coder un plugin, je repartais &amp;laquo; from scratch &amp;raquo;. Avec le framework jQuery UI, toute la logique est d&amp;eacute;j&amp;agrave; pr&amp;eacute;-pens&amp;eacute;e, que ce soit pour le JavaScript que pour le CSS. Plus fort, je peux utiliser facilement le syst&amp;egrave;me d'h&amp;eacute;ritage pour modifier un plugin existant.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;Passons &amp;agrave; la pratique. Notre exemple est basique : transformation d'un DIV en un bloc avec titre.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Le code de base d'un widget jQuery UI&lt;/h2&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code21&quot; class=&quot;cm-s-default&quot;&gt;// Pour créer mon plugin il suffit d'appeller la méthode $.widget
// Le 1er paramètre est le nom de mon plugin préfixé par demo. (le namespace du widget, ui étant le namespace de jQuery UI)
// Le 2eme paramètres est un objet json de paramétrage du plugin
$.widget(&amp;quot;demo.bloc&amp;quot;, {
    // options par défaut du widget 
    // modifiables à la construction 
    // mais aussi après la construction du widget 
    options: {
        title: 'Titre'
    },

    // Une variable interne 
    // contient l'objet jQuery du titre du bloc
     uiBlocTitle: null,

    // La fonction _create est appelé à la construction du widget
    // la variable d'instance this.element contient un objet jQuery
    // contenant l'élément sur lequel porte le widget
    _create: function() {
        this.element.addClass('uiBloc');
        this._title() ;
    },

    // Toutes les fonctions commençant par un underscore
    // sont des fonctions internes
     _title: function() {
        this.uiBlocTitle = $('&amp;lt;h5&amp;gt;&amp;lt;/h5&amp;gt;').text(this.options.title).prependTo(this.element);
     },

    // Les fonctions ne commençant pas par un underscore
    // sont des fonctions pouvant être appelées de l'extérieur
    title: function(text) {
        if (typeof(text)!= 'undefined') {
            // la variable text a été passée en paramètre
            // Modification du texte
            // et ne pas oublier de retourner l'élément (this.element)
            // pour rendre possible le chainage de fonction
            returnthis.uiBlocTitle.text(text);
        } else {
            // la variable text n'a pas été passée en paramètre
            // On retourne le texte actuellement contenu dans l'élément
            returnthis.uiBlocTitle.text();
        }
    }
});&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2&gt;Voici maintenant le code d'utilisation&lt;/h2&gt;
&lt;p&gt;&lt;pre&gt;&lt;code id=&quot;code22&quot; class=&quot;cm-s-default&quot;&gt;&amp;lt;div id=&amp;quot;monbloc&amp;quot;&amp;gt;
 &amp;lt;p&amp;gt;Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. Even the all-powerful Pointing has no control about the blind texts it is an almost unorthographic life One day however a small line of blind text by the name of Lorem Ipsum decided to leave for the far World of Grammar. The Big Oxmox advised her not to do so, because there were thousands of bad Commas, wild Question Marks and devious Semikoli, but the Little Blind Text didn?t listen. She packed her seven versalia, put her initial into the belt and made herself on the way. When she reached the first hills of the Italic Mountains, she had a last view back on the skyline of her hometown Bookmarksgrove, the headline of Alphabet Village and the subline of her own road, the Line Lane. Pityful a rethoric question ran over her cheek, then &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
 &amp;lt;button id=&amp;quot;action1&amp;quot;&amp;gt;Changer le titre&amp;lt;/button&amp;gt;
 &amp;lt;button id=&amp;quot;action2&amp;quot;&amp;gt;Alert : le titre&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;static/js/jquery-ui/js/jquery-ui-1.8.14.custom.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
(function($) {
     $(function() {
         // Appel de la construction du widget
         // en surchargeant les options par défaut
         $('#monbloc').bloc({title : 'Hello world'});

        // Un click sur le bouton Change modifie le texte
        // On rappelle la fonction bloc sur l'élément
        // Le premier paramètre est le nom de la fonction interne (title)
        // Le deuxième est le paramètre de la fonction interne
        $('#action1').click(function() {
            $('#monbloc').bloc('title', 'Bonjour monde');
        }) ;

         // Un click sur le bouton Alert affiche le texte en cours dans une alert
         $('#action2').click(function() {
             alert($('#monbloc').bloc('title'));
         }) ;
     });
})(jQuery);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2&gt;Et maintenant la d&amp;eacute;mo&lt;/h2&gt;
&lt;p&gt;&lt;iframe src=&quot;http://jsfiddle.net/noviuslabs/m8AZk/embedded/result/&quot; width=&quot;100%&quot; height=&quot;300px&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;La suite : le skinnage&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://nova.li/qFCC4Z&quot;&gt;Passons &amp;agrave; la deuxi&amp;egrave;me &amp;eacute;tape, la mise en forme de notre UI&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</description>
       <dc:creator>Gilles Felix </dc:creator>
       <pubDate>Mon, 11 Jul 2011 12:24:00 +0200</pubDate>
   </item>
</channel>
</rss>
