<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Olivier El Mekki</title>
	<atom:link href="http://blog.olivier-elmekki.com/category/blog/wp-rss2.php" rel="self" type="application/rss+xml" />
	<link>http://blog.olivier-elmekki.com</link>
	<description></description>
	<pubDate>Sun, 30 Jan 2011 12:41:11 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.5</generator>
	<language>en</language>
			<item>
		<title>Get rake routes to recognize constraint classes in rails</title>
		<link>http://blog.olivier-elmekki.com/2011/01/30/get-rake-routes-to-recognize-constraint-classes-in-rails/</link>
		<comments>http://blog.olivier-elmekki.com/2011/01/30/get-rake-routes-to-recognize-constraint-classes-in-rails/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 12:23:18 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=438</guid>
		<description><![CDATA[I&#8217;ve been playing recently with the new rails-3 route constraints behaviour. Quite nice, actually, I really enjoy being able to add total custom code to determine if a route match. Of course (?), my first use of that has been subdomain constraints. Here is an example :

  constraints&#40; ClientSubdomain &#41; do
    [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been playing recently with the new rails-3 route constraints behaviour. Quite nice, actually, I really enjoy being able to add total custom code to determine if a route match. Of course (?), my first use of that has been subdomain constraints. Here is an example :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;">  constraints<span style="color:#006600; font-weight:bold;">&#40;</span> ClientSubdomain <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    resource <span style="color:#ff3333; font-weight:bold;">:organization</span>, <span style="color:#ff3333; font-weight:bold;">:only</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#40;</span> show edit update destroy <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      get <span style="color:#996600;">'close'</span>, <span style="color:#ff3333; font-weight:bold;">:on</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:member</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    root <span style="color:#ff3333; font-weight:bold;">:to</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'static_page#get_page'</span>, <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'home_client'</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  constraints<span style="color:#006600; font-weight:bold;">&#40;</span> AdminSubdomain <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    scope <span style="color:#ff3333; font-weight:bold;">:module</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'admin'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      resources <span style="color:#ff3333; font-weight:bold;">:organizations</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    root <span style="color:#ff3333; font-weight:bold;">:to</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'admin/organizations#index'</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>So here, if I&#8217;m on the admin subdomain, I can handle multiple organizations, my clients ones. And if I am on a client subdomain, the organization resource is a singleton (client must only handle its own organization, right?).<br />
Ok, let&#8217;s see what rake routes outputs.</p>
<pre>
close_organization GET    /organization/close(.:format)     {:action=>"close", :controller=>"organizations"}
 edit_organization GET    /organization/edit(.:format)      {:action=>"edit", :controller=>"organizations"}
      organization GET    /organization(.:format)           {:action=>"show", :controller=>"organizations"}
                   PUT    /organization(.:format)           {:action=>"update", :controller=>"organizations"}
                   DELETE /organization(.:format)           {:action=>"destroy", :controller=>"organizations"}
              root        /(.:format)                       {:action=>"get_page", :controller=>"static_page"}
     organizations GET    /organizations(.:format)          {:action=>"index", :controller=>"admin/organizations"}
                   POST   /organizations(.:format)          {:action=>"create", :controller=>"admin/organizations"}
  new_organization GET    /organizations/new(.:format)      {:action=>"new", :controller=>"admin/organizations"}
                   GET    /organizations/:id/edit(.:format) {:action=>"edit", :controller=>"admin/organizations"}
                   GET    /organizations/:id(.:format)      {:action=>"show", :controller=>"admin/organizations"}
                   PUT    /organizations/:id(.:format)      {:action=>"update", :controller=>"admin/organizations"}
                   DELETE /organizations/:id(.:format)      {:action=>"destroy", :controller=>"admin/organizations"}
              root        /(.:format)                       {:action=>"index", :controller=>"admin/organizations"}
</pre>
<p>Erf, not really helpful.</p>
<p>After playing a while with mapper, routeset and routes, I came to a solution.</p>
<h2>Monkey patch for Constraints</h2>
<p>First, we need to expose Constraints#constraints to the world. Create a lib/route_constraints.rb:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">module</span> ActionDispatch
  <span style="color:#9966CC; font-weight:bold;">module</span> Routing
    <span style="color:#9966CC; font-weight:bold;">class</span> Mapper
      <span style="color:#9966CC; font-weight:bold;">class</span> Constraints
        attr_reader <span style="color:#ff3333; font-weight:bold;">:constraints</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Be sure to require it in config/environment.rb.</p>
<h2>Rake task</h2>
<p>Then, put this content in lib/tasks/route_with_constraints.rake:<br />
<a href="https://gist.github.com/802375">Gist</a></p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;">namespace <span style="color:#ff3333; font-weight:bold;">:routes</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  desc <span style="color:#996600;">'Print out all defined routes in match order, with names, per constraint class. Target specific constraint class with CONSTRAINT=x. Target specific controller with CONTROLLER=x.'</span>
  task <span style="color:#ff3333; font-weight:bold;">:constrained</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:environment</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Rails.<span style="color:#9900CC;">application</span>.<span style="color:#9900CC;">reload_routes</span>!
&nbsp;
    constraints_routes = <span style="color:#CC00FF; font-weight:bold;">Hash</span>.<span style="color:#9900CC;">new</span>
&nbsp;
    Rails.<span style="color:#9900CC;">application</span>.<span style="color:#9900CC;">routes</span>.<span style="color:#9900CC;">routes</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |route|
      group = <span style="color:#006600; font-weight:bold;">&#40;</span>route.<span style="color:#9900CC;">app</span>.<span style="color:#9966CC; font-weight:bold;">class</span> == <span style="color:#6666ff; font-weight:bold;">ActionDispatch::Routing::Mapper::Constraints</span> ? route.<span style="color:#9900CC;">app</span>.<span style="color:#9900CC;">constraints</span>.<span style="color:#9900CC;">to_s</span> : <span style="color:#996600;">'No constraint class'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      constraints_routes<span style="color:#006600; font-weight:bold;">&#91;</span>group<span style="color:#006600; font-weight:bold;">&#93;</span> ||= <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
      constraints_routes<span style="color:#006600; font-weight:bold;">&#91;</span>group<span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">&lt;</span> route
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    requested_constraint = ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'CONSTRAINT'</span><span style="color:#006600; font-weight:bold;">&#93;</span>
&nbsp;
    constraints_routes.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |group, all_routes|
      <span style="color:#9966CC; font-weight:bold;">if</span> requested_constraint.<span style="color:#0000FF; font-weight:bold;">nil</span>? <span style="color:#9966CC; font-weight:bold;">or</span> group == requested_constraint
        <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;<span style="color:#000099;">\n</span><span style="color:#000099;">\n</span>Constraint class : #{group}<span style="color:#000099;">\n</span><span style="color:#000099;">\n</span>&quot;</span>
&nbsp;
        <span style="color:#9966CC; font-weight:bold;">if</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'CONTROLLER'</span><span style="color:#006600; font-weight:bold;">&#93;</span>
          all_routes = all_routes.<span style="color:#CC0066; font-weight:bold;">select</span><span style="color:#006600; font-weight:bold;">&#123;</span> |route| route.<span style="color:#9900CC;">defaults</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:controller</span><span style="color:#006600; font-weight:bold;">&#93;</span> == ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'CONTROLLER'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
        routes = all_routes.<span style="color:#9900CC;">collect</span> <span style="color:#9966CC; font-weight:bold;">do</span> |route|
&nbsp;
          reqs = route.<span style="color:#9900CC;">requirements</span>.<span style="color:#9900CC;">dup</span>
          reqs<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:to</span><span style="color:#006600; font-weight:bold;">&#93;</span> = route.<span style="color:#9900CC;">app</span> <span style="color:#9966CC; font-weight:bold;">unless</span> route.<span style="color:#9900CC;">app</span>.<span style="color:#9966CC; font-weight:bold;">class</span>.<span style="color:#9900CC;">name</span>.<span style="color:#9900CC;">to_s</span> =~ <span style="color:#006600; font-weight:bold;">/</span>^<span style="color:#6666ff; font-weight:bold;">ActionDispatch::Routing</span><span style="color:#006600; font-weight:bold;">/</span>
          reqs = reqs.<span style="color:#9900CC;">empty</span>? ? <span style="color:#996600;">&quot;&quot;</span> : reqs.<span style="color:#9900CC;">inspect</span>
&nbsp;
          <span style="color:#006600; font-weight:bold;">&#123;</span>:name <span style="color:#006600; font-weight:bold;">=&gt;</span> route.<span style="color:#9900CC;">name</span>.<span style="color:#9900CC;">to_s</span>, <span style="color:#ff3333; font-weight:bold;">:verb</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> route.<span style="color:#9900CC;">verb</span>.<span style="color:#9900CC;">to_s</span>, <span style="color:#ff3333; font-weight:bold;">:path</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> route.<span style="color:#9900CC;">path</span>, <span style="color:#ff3333; font-weight:bold;">:reqs</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> reqs<span style="color:#006600; font-weight:bold;">&#125;</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
        routes.<span style="color:#9900CC;">reject</span>! <span style="color:#006600; font-weight:bold;">&#123;</span> |r| r<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:path</span><span style="color:#006600; font-weight:bold;">&#93;</span> =~ <span style="color:#006600; font-weight:bold;">%</span>r<span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">/</span>rails<span style="color:#006600; font-weight:bold;">/</span>info<span style="color:#006600; font-weight:bold;">/</span>properties<span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;"># Skip the route if it's internal info route</span>
&nbsp;
        name_width = routes.<span style="color:#9900CC;">map</span><span style="color:#006600; font-weight:bold;">&#123;</span> |r| r<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:name</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">length</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">max</span>
        verb_width = routes.<span style="color:#9900CC;">map</span><span style="color:#006600; font-weight:bold;">&#123;</span> |r| r<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:verb</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">length</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">max</span>
        path_width = routes.<span style="color:#9900CC;">map</span><span style="color:#006600; font-weight:bold;">&#123;</span> |r| r<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:path</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">length</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">max</span>
&nbsp;
        routes.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |r|
          <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}&quot;</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Ok, now we have a rake routes:constrained task. Let see its output :</p>
<pre>
Constraint class : No constraint class

Constraint class : AdminSubdomain

   organizations GET    /organizations(.:format)          {:action=>"index", :controller=>"admin/organizations"}
                 POST   /organizations(.:format)          {:action=>"create", :controller=>"admin/organizations"}
new_organization GET    /organizations/new(.:format)      {:action=>"new", :controller=>"admin/organizations"}
                 GET    /organizations/:id/edit(.:format) {:action=>"edit", :controller=>"admin/organizations"}
                 GET    /organizations/:id(.:format)      {:action=>"show", :controller=>"admin/organizations"}
                 PUT    /organizations/:id(.:format)      {:action=>"update", :controller=>"admin/organizations"}
                 DELETE /organizations/:id(.:format)      {:action=>"destroy", :controller=>"admin/organizations"}
            root        /(.:format)                       {:action=>"index", :controller=>"admin/organizations"}

Constraint class : ClientSubdomain

close_organization GET    /organization/close(.:format) {:action=>"close", :controller=>"organizations"}
 edit_organization GET    /organization/edit(.:format)  {:action=>"edit", :controller=>"organizations"}
      organization GET    /organization(.:format)       {:action=>"show", :controller=>"organizations"}
                   PUT    /organization(.:format)       {:action=>"update", :controller=>"organizations"}
                   DELETE /organization(.:format)       {:action=>"destroy", :controller=>"organizations"}
              root        /(.:format)                   {:action=>"get_page", :controller=>"static_page"}
</pre>
<p>Way better :)</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=438" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2011/01/30/get-rake-routes-to-recognize-constraint-classes-in-rails/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Zookshop : création de boutiques en ligne à faible coût</title>
		<link>http://blog.olivier-elmekki.com/2010/11/13/zookshop-creation-de-boutiques-en-ligne-a-faible-cout/</link>
		<comments>http://blog.olivier-elmekki.com/2010/11/13/zookshop-creation-de-boutiques-en-ligne-a-faible-cout/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 19:19:30 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[Non classé]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=431</guid>
		<description><![CDATA[Travailleurs du web, combien de fois avez-vous été contactés par des clients souhaitant créer une boutique en ligne pour finalement vous rendre compte que leur budget était tout à fait insuffisant?

La passion enfin partagée
Internet offre d&#8217;incroyables possibilités de développement économiques. Tout un chacun a sa propre passion ou son propre produit « terroir » qui [...]]]></description>
			<content:encoded><![CDATA[<p>Travailleurs du web, combien de fois avez-vous été contactés par des clients souhaitant créer une boutique en ligne pour finalement vous rendre compte que leur budget était tout à fait insuffisant?</p>
<p><span id="more-431"></span></p>
<h3>La passion enfin partagée</h3>
<p>Internet offre d&#8217;incroyables possibilités de développement économiques. Tout un chacun a sa propre passion ou son propre produit « terroir » qui n&#8217;attend qu&#8217;une initiative pour atteindre le monde. L&#8217;import/export était quelque chose de relativement rare pour les particuliers avant l&#8217;émergence d&#8217;internet. Je me souviens encore avoir rêvé, étant enfant, de ces fabuleux jeux de super nintendo qui ne sortaient qu&#8217;au Japon et que je n&#8217;ai jamais pu m&#8217;offrir du simple fait que le coût de leur importation était exhorbitant. Aujourd&#8217;hui, j&#8217;achète des t-shirts rares aux États-unis pour le même prix que ce qu&#8217;on trouve dans des boutiques locales, comme H&#038;M. </p>
<p>Je ne me ferais pas le défenseur du marché commun et de la mondialisation ; cependant le commerce via internet se montre particulièrement efficace (en terme d&#8217;offre et de coût) lorsqu&#8217;on recherche quelque chose de particulièrement rare et localisé : aujourd&#8217;hui, un vietnamien peut <a href="http://www.rubylane.com/item/535034-F0709-0386/French-Provincial-Bombe-Comtoise-Pine">acheter une horloge comptoise</a> au presque même prix que nous la trouverions chez nous.</p>
<p>En ces temps de chômage important, il y a ici une vraie opportunité : chacun peut mettre en place un commerce international sans avoir à avoir pignon sur rue dans chaque pays livré. Conséquence directe du changement d&#8217;échelle, nous pouvons concentrer notre activité sur un produit qui ne suffirait pas à nous faire vivre si nous étions restés sur l&#8217;échelle locale.</p>
<h3>Le coût d&#8217;une boutique en ligne</h3>
<p>Reste un problème majeur. Si créer une boutique en ligne à dimension internationale représente un coût ridicule par rapport à la même chose sans internet, il n&#8217;en reste pas moins que c&#8217;est très onéreux.</p>
<p>Le développement de la boutique elle-même représente en général entre 5000 et 10000 euros, selon la complexité. En cas de concurrence, le coup de référencement peut représenter 2000 à 5000 euros supplémentaires (cela dit, mieux vaut se lancer dans un projet sans concurrence web si on veut s&#8217;assurer de sa réussite).</p>
<p>Cela représente donc un investissement important, surtout pour une personne au chômage.</p>
<h3>Kolibria à la rescousse</h3>
<p>Mon ami Christophe Maximin de <a href="http://www.kolibria.com">Kolibria</a> vient de lancer un service web qui pourrait bien changer la donne.</p>
<p>Ce service s&#8217;appelle <a href="http://www.zookshop.fr">Zookshop</a>, et ne propose ni plus ni moins que de créer une boutique en ligne pour à partir de 19euros par mois, ce qui représente ce que coûte habituellement le seul hébergement d&#8217;une boutique.</p>
<p>Concrètement, cela veut dire qu&#8217;aujourd&#8217;hui, n&#8217;importe qui peut créer une entreprise individuelle (qui permet de n&#8217;être imposé que sur son bénéfice réel), créer sa boutique pour 20euros, et commencer à vendre des produits.</p>
<h3>La fin du développement classique?</h3>
<p>Alors maintenant, nous autres développeurs, devons-nous nous dire que ce fumier de Christophe a pourri notre activité? :)</p>
<p>Personnellement, je dirais que non (bisou Christophe). Cela me fait penser aux services de création de site web, qu&#8217;ils soient moyens et gratuits (comme myspace) ou payants et bien faits (comme &lt;insérez votre service préféré&gt;). Il m&#8217;arrive régulièrement de me faire contacter par des personnes ayant un tel type de site, qui désire passer à une autre échelle en ayant un site totalement personnalisé. Et pourtant, ma clientèle de base est principalement faite de graphistes ou autres personnes du métier cherchant un développeur ; j&#8217;imagine que ces demandes sont encore plus fréquentes pour les personnes qui traitent directement les clients finaux.</p>
<p>Certes, Zookshop propose toutes les fonctionnalités standard qu&#8217;une personne attend de sa boutique web : gestion du catalogue, des factures, des zones de livraisons, des commandes, des bons de réductions, du blog, etc. Il est même possible d&#8217;embaucher un graphiste/intégrateur ou un seo et de leur faire refaire la structure des pages.</p>
<p>Cependant, il arrivera toujours (ou du moins : souvent) que la personne gérant une boutique qui commence a bien marcher veuille des fonctionnalités atypiques, qu&#8217;elle estimera appropriées aux produits qu&#8217;elle vend. Dans ce cas, il faudra bel et bien une boutique personnalisée, et les bénéfices déjà réaliser permettront d&#8217;envisager sa création sereinement.</p>
<p>Reste que ZookShop est une incroyable opportunité pour qui veut se lancer dans l&#8217;aventure du commerce en ligne sans ne disposer d&#8217;aucuns moyens, ou pour qui a des besoins très simples. C&#8217;est un type de clientèle qui n&#8217;aurait de toute façon trouvé personne pour réaliser sa boutique.</p>
<p>Un grand merci, donc, à Kolibria, pour l&#8217;évolution sociale qu&#8217;il a apporté :)</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=431" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2010/11/13/zookshop-creation-de-boutiques-en-ligne-a-faible-cout/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Le développement top-down en uad</title>
		<link>http://blog.olivier-elmekki.com/2010/01/21/le-developpement-top-down-en-uad/</link>
		<comments>http://blog.olivier-elmekki.com/2010/01/21/le-developpement-top-down-en-uad/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 21:39:04 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=424</guid>
		<description><![CDATA[Cet article fait suite à la conversation que j&#8217;ai eue avec Patrick Fratczak sur la manière de faire du TDD.
Voici donc la méthode que j&#8217;emploi pour faire du user acceptance testing. L&#8217;exemple décrit ici utilise rails, cucumber et rspec, mais cela fonctionne également bien avant Typolight, cucumber et phpspec.

Soit, je développe un site pour un [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article fait suite à <a href="http://blog.olivier-elmekki.com/2008/10/17/maitriser-les-tests-unitaires-dans-ruby-on-rails/#comments">la conversation que j&#8217;ai eue avec Patrick Fratczak sur la manière de faire du TDD</a>.</p>
<p>Voici donc la méthode que j&#8217;emploi pour faire du user acceptance testing. L&#8217;exemple décrit ici utilise rails, cucumber et rspec, mais cela fonctionne également bien avant Typolight, cucumber et phpspec.</p>
<p><span id="more-424"></span></p>
<p>Soit, je développe un site pour un client qui vend des peintures. Une des fonctionnalité est le catalogue de peinture. Pour compliquer un peu cet exemple (et le rendre donc plus proche de la réalité), disons que ce client veut que lorsqu&#8217;on visionne la page d&#8217;une peinture, on voit le nombre d&#8217;autres visiteurs qui la visionne en même temps. Je lui dis d&#8217;abord que cette fonctionnalité n&#8217;est pas rentable, si on prend en compte son temps/coût de développement et son retour sur investissement. Mon client m&#8217;assure que c&#8217;est rentable, grâce au principe « le monde attire le monde » : si un visiteur remarque que d&#8217;autres personnes regarde la peinture en même temps que lui, il aura plus envie de l&#8217;acheter.</p>
<p>Dans la user story du catalogue, on donc trouve le scénario suivant :</p>
<pre>
Scénario: Voir le détail d'une peinture
  Lorsque je vais sur la page de la liste des peinture
  Et que je suis le lien de la première peinture
  Alors je dois voir sa photo
  Et je dois voir son titre
  Et je dois voir son auteur
  Et je dois voir son prix
  Et je dois voir le nombre de personnes qui visualisent ce produit actuellement
</pre>
<p>Une fois que le client a validé ce scénario, j&#8217;écris les steps cucumber suivantes :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">Then</span> <span style="color:#006600; font-weight:bold;">/</span>je dois voir sa photo<span style="color:#006600; font-weight:bold;">/</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  response.<span style="color:#9900CC;">should</span> have_selector<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'#paint .picture img[src*=&quot;paint-1-full.jpg&quot;]'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">Then</span> <span style="color:#006600; font-weight:bold;">/</span>je dois voir son titre<span style="color:#006600; font-weight:bold;">/</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  response.<span style="color:#9900CC;">should</span> have_selector<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'#paint h1.title:contains(&quot;Paint 1 test&quot;)'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">Then</span> <span style="color:#006600; font-weight:bold;">/</span>je dois voir son auteur<span style="color:#006600; font-weight:bold;">/</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  response.<span style="color:#9900CC;">should</span> have_selector<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'#paint .author:contains(&quot;Paint 1 author&quot;)'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">Then</span> <span style="color:#006600; font-weight:bold;">/</span>je dois voir son prix<span style="color:#006600; font-weight:bold;">/</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  response.<span style="color:#9900CC;">should</span> have_selector<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'#paint .price:contains(&quot;10€&quot;)'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">Then</span> <span style="color:#006600; font-weight:bold;">/</span>je dois voir le nombre de personnes qui visualisent ce produit actuellement<span style="color:#006600; font-weight:bold;">/</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  response.<span style="color:#9900CC;">should</span> have_selector<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'#paint .viewer-count:contains(&quot;5&quot;)'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Cucumber, couplé à webrat, a cet avantage de permettre de faire des tests précis des vues à base de sélecteur CSS3. De nombreuses autres méthodes sont permises, et notament toute une gamme de méthodes qui executent une action tout en la testant, par exemple .click_link( link ) fait une assertion sur l&#8217;existence de ce lien, puis le suit effectivement. Pour ma part, j&#8217;aime bien être le plus précis possible dans les sélecteurs dans mes steps afin de me permettre de composer d&#8217;un trait mes vues ensuite.</p>
<p>Ayant ces steps, je peux maintenant écrire ma vue :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;">&lt;div id=&quot;paint&quot;&gt;
  &lt;h1 class=&quot;title&quot;&gt;&lt; %= @paint.title -%&gt;&lt;/h1&gt;
&nbsp;
  &lt;div class=&quot;picture&quot;&gt;
    &lt;img src=&quot;<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#0066ff; font-weight:bold;">@paint</span>.<span style="color:#9900CC;">imageSRC</span> <span style="color:#006600; font-weight:bold;">-%/&gt;</span><span style="color:#996600;">&quot; alt=&quot;</span>Photo de <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= <span style="color:#0066ff; font-weight:bold;">@paint</span>.<span style="color:#9900CC;">title</span> <span style="color:#006600; font-weight:bold;">-%&gt;</span>&quot; /&gt;
  &lt;/div&gt;&lt;!-- .picture --&gt;
&nbsp;
  &lt;div class=&quot;author&quot;&gt;
    &lt; %= @paint.author -%&gt;
  &lt;/div&gt;&lt;!-- .author --&gt;
&nbsp;
  &lt;div class=&quot;price&quot;&gt;
    &lt; %= &quot;%.2f&quot; % @paint.price -%&gt;€
  &lt;/div&gt;&lt;!-- .price --&gt;
&nbsp;
  &lt;div class=&quot;viewer-count&quot;&gt;
    &lt; %= @viewer_count -%&gt;
  &lt;/div&gt;&lt;!-- .viewer-count --&gt;
&lt;/div&gt;&lt;!-- #paint --&gt;</pre></div></div>

<p>Je sais maintenant que mon controller doit assigner @paint et @viewer_count. J&#8217;ai également déjà de bon indices sur ce dont je vais avoir besoin dans mes modèles et ma base de donnée. Je peux maintenant écrire les test de mon controller. Qu&#8217;est-ce que ce controller doit faire? Il doit assigner un modèle Paint et calculer le nombre de personnes qui voient actuellement cet article. Réflichissant à cette deuxième fonctionnalité, je me dis que cela doit être une méthode de classe de Visitor, qui vérifiera les journaux de visite pour une page donnée. Je n&#8217;ai pas besoin d&#8217;en savoir plus pour l&#8217;instant.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec_helper'</span>
&nbsp;
describe PaintsController <span style="color:#9966CC; font-weight:bold;">do</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> mock_paint<span style="color:#006600; font-weight:bold;">&#40;</span>stubs=<span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@mock_paint</span> ||= mock_model<span style="color:#006600; font-weight:bold;">&#40;</span>Paint, stubs<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  describe <span style="color:#996600;">&quot;GET show&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    it <span style="color:#996600;">&quot;assigns the requested paint as @paint and the current viewers count as @viewer_count&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      Paint.<span style="color:#9900CC;">stub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:find</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">&quot;1&quot;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span> mock_paint<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Paint 1 test'</span>, <span style="color:#ff3333; font-weight:bold;">:imageSRC</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'paint-1-full.jpg'</span>, <span style="color:#ff3333; font-weight:bold;">:author</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Paint 1 author'</span>, <span style="color:#ff3333; font-weight:bold;">:price</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'10.0'</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
      Visitor.<span style="color:#9900CC;">stub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:viewer_count</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'/paints/show/1'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
      get <span style="color:#ff3333; font-weight:bold;">:show</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;1&quot;</span>
      assigns<span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:paint</span> <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> mock_paint <span style="color:#006600; font-weight:bold;">&#41;</span>
      assigns<span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:viewer_count</span> <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Je peux maintenant écrire mon controller.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> PaintsController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
  <span style="color:#9966CC; font-weight:bold;">def</span> show
    <span style="color:#0066ff; font-weight:bold;">@paint</span>        = Paint.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span> params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@viewer_count</span> = Visitor.<span style="color:#9900CC;">viewer_count</span><span style="color:#006600; font-weight:bold;">&#40;</span> request.<span style="color:#9900CC;">request_uri</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    respond_to <span style="color:#9966CC; font-weight:bold;">do</span> |format|
      <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">html</span> <span style="color:#008000; font-style:italic;"># show.html.erb</span>
      <span style="color:#CC0066; font-weight:bold;">format</span>.<span style="color:#9900CC;">xml</span>  <span style="color:#006600; font-weight:bold;">&#123;</span> render <span style="color:#ff3333; font-weight:bold;">:xml</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0066ff; font-weight:bold;">@paint</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Désormais, je sais que j&#8217;ai besoin de deux modèles : Paint et Visitor. Je sais également à quoi ils doivent répondre : :title, :imageSRC, :author et :price pour les instances de Paint, :viewer_count pour la classe Visitor. Qu&#8217;est-ce qui sera attribut et qu&#8217;est-ce qui sera méthode dans tout cela? Je réalise maintenant que tous ce à quoi doit répondre une instance de paint est un attribut simple. Il s&#8217;agira donc d&#8217;un modèle simple avec title, imageSRC, author et price en tant que champs de la table `paints`.</p>
<p>À ce stade, je peux utiliser le generateur rspec_model pour créer ce modèle simple et ses tests :<br />
./script/generate rspec_model Paint title:string imageSRC:string author:string price:float</p>
<p>Visitor est un modèle moins simple. Que sais-je sur lui? D&#8217;abord, il doit répondre à la méthode :viewer_count. J&#8217;écris donc tout de suite ce test.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec_helper'</span>
&nbsp;
describe Visitor <span style="color:#9966CC; font-weight:bold;">do</span>
  it <span style="color:#996600;">&quot;should give the viewer count&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Visitor.<span style="color:#9900CC;">viewer_count</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'/paints/show/1'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Je m&#8217;interroge maintenant sur comment retrouver ce nombre. Les visites doivent être loggée dans une table. Un visiteur est considéré comment visitant une page s&#8217;il l&#8217;a visité dans les 5 précédentes minutes. J&#8217;identifie un visiteur par son IP. Je dois effacer les anciennes visites pour ne pas surcharger ma db. Ok, j&#8217;ai ce qu&#8217;il faut pour écrire mes specs.</p>
<p>D&#8217;abord, je sais que chaque visite doit être loggé. Cela passera donc par un before_filter dans application_controller.rb . Je modifie donc mon fichier de test de mon controller ainsi :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec_helper'</span>
&nbsp;
describe PaintsController <span style="color:#9966CC; font-weight:bold;">do</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> mock_paint<span style="color:#006600; font-weight:bold;">&#40;</span>stubs=<span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@mock_paint</span> ||= mock_model<span style="color:#006600; font-weight:bold;">&#40;</span>Paint, stubs<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  before<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:each</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Visitor.<span style="color:#9900CC;">stub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:log</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  describe <span style="color:#996600;">&quot;GET show&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    it <span style="color:#996600;">&quot;assigns the requested paint as @paint and the current viewers count as @viewer_count&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      Paint.<span style="color:#9900CC;">stub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:find</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">&quot;1&quot;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span> mock_paint<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Paint 1 test'</span>, <span style="color:#ff3333; font-weight:bold;">:imageSRC</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'paint-1-full.jpg'</span>, <span style="color:#ff3333; font-weight:bold;">:author</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Paint 1 author'</span>, <span style="color:#ff3333; font-weight:bold;">:price</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'10.0'</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
      Visitor.<span style="color:#9900CC;">stub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:viewer_count</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">'paints/show/1'</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
      get <span style="color:#ff3333; font-weight:bold;">:show</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;1&quot;</span>
      assigns<span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:paint</span> <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> mock_paint <span style="color:#006600; font-weight:bold;">&#41;</span>
      assigns<span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:viewer_count</span> <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Je peux maintenant écrire le before_filter :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> ApplicationController <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActionController::Base</span>
  before_filter <span style="color:#ff3333; font-weight:bold;">:log_visit</span>
  helper <span style="color:#ff3333; font-weight:bold;">:all</span> <span style="color:#008000; font-style:italic;"># include all helpers, all the time</span>
  protect_from_forgery <span style="color:#008000; font-style:italic;"># See ActionController::RequestForgeryProtection for details</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> log_visit
    Visitor.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span> request.<span style="color:#9900CC;">request_uri</span>, request.<span style="color:#9900CC;">ip</span>, <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Cela m&#8217;en dit plus sur mon modèle Visitor. Il possède une méthode de classe :log. Celle ci enregistrera l&#8217;ip, la page et la date. Cette méthode devra également être responsable du vidage de la table. Cela fait une requête de plus à chaque visite, mais ça maintiendra la table presque vide.  Je peux donc écrire son test :</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec_helper'</span>
&nbsp;
describe Visitor <span style="color:#9966CC; font-weight:bold;">do</span>
  it <span style="color:#996600;">&quot;should give the viewer count&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Visitor.<span style="color:#9900CC;">viewer_count</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  it <span style="color:#996600;">&quot;should log visits&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Visitor.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:delete_all</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    ip, page, date = <span style="color:#996600;">'127.0.0.1'</span>, <span style="color:#996600;">'/show/paint/1'</span>, <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>
    Visitor.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:create</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> page, <span style="color:#ff3333; font-weight:bold;">:ip</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> ip, <span style="color:#ff3333; font-weight:bold;">:date</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> time <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span> page, id, date <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Je sais maintenant que mon modèle ma table visitors possède les champs :page, :ip et :date. Je peux générer le modèle.<br />
./script/generate model Visitor page:string ip:string date:datetime</p>
<p>Et je peux implémenter ma méthode :log</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Visitor <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  attr_accessible         <span style="color:#ff3333; font-weight:bold;">:page</span>, <span style="color:#ff3333; font-weight:bold;">:ip</span>, <span style="color:#ff3333; font-weight:bold;">:date</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span> page, ip, date <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">delete_all</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;date &lt; ?&quot;</span>, 5.<span style="color:#9900CC;">minutes</span>.<span style="color:#9900CC;">ago</span>.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:db</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">create</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> page, <span style="color:#ff3333; font-weight:bold;">:ip</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> ip, <span style="color:#ff3333; font-weight:bold;">:date</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> date <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Je sais également comment retrouver le nombre de visiteurs d&#8217;une page. Je complète donc son test :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec_helper'</span>
&nbsp;
describe Visitor <span style="color:#9966CC; font-weight:bold;">do</span>
  it <span style="color:#996600;">&quot;should give the viewer count&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    page = <span style="color:#996600;">'/paints/show/1'</span>
    Visitor.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:all</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;page = ?&quot;</span>, page <span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#006666;">1</span>, <span style="color:#006666;">2</span>, <span style="color:#006666;">3</span>, <span style="color:#006666;">4</span>, <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">viewer_count</span><span style="color:#006600; font-weight:bold;">&#40;</span> page <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> equal<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  it <span style="color:#996600;">&quot;should log visits&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    Visitor.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:delete_all</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    ip, page, date = <span style="color:#996600;">'127.0.0.1'</span>, <span style="color:#996600;">'/show/paint/1'</span>, <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>
    Visitor.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:create</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> page, <span style="color:#ff3333; font-weight:bold;">:ip</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> ip, <span style="color:#ff3333; font-weight:bold;">:date</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> time <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span> page, id, date <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Et j&#8217;écris la méthode :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Visitor <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  attr_accessible         <span style="color:#ff3333; font-weight:bold;">:page</span>, <span style="color:#ff3333; font-weight:bold;">:ip</span>, <span style="color:#ff3333; font-weight:bold;">:date</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span> page, ip, date <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">delete_all</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;date &lt; ?&quot;</span>, 5.<span style="color:#9900CC;">minutes</span>.<span style="color:#9900CC;">ago</span>.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:db</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    Visitor.<span style="color:#9900CC;">create</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> page, <span style="color:#ff3333; font-weight:bold;">:ip</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> ip, <span style="color:#ff3333; font-weight:bold;">:date</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> date <span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">viewer_count</span><span style="color:#006600; font-weight:bold;">&#40;</span> page <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">return</span> Visitor.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;page = ?&quot;</span>, page <span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">length</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>À ce point, j&#8217;ai terminé l&#8217;implémentation de mon scénario. Il ne me reste plus qu&#8217;à le tester. Les specs doivent déjà passer, Pour faire passer les tests de cucumber, je dois d&#8217;abord écrire ma route et inclure mes fixtures (nombreux sont ceux qui détestent les fixtures, aujourd&#8217;hui, je les trouve personnellement plus simple d&#8217;utilisation dans le cadre de cucumber).</p>
<p>L&#8217;immense avantage de cette méthode est de rendre tout évident. C&#8217;est un no-brainer total et il n&#8217;y a qu&#8217;à développer, au sens strict. Plutôt que de construire un outil en tentant d&#8217;imaginer ses usages, puis d&#8217;adapter les usages en fonction de l&#8217;outil créé ( schéma du type : on va des modèles aux vues ), je défini d&#8217;abord l&#8217;usage en disant ce que mes outils doivent faire, et je les construis en conséquence ( schéma du type : vues vers modèles ).</p>
<p>L&#8217;immense inconvénient est que les tests ne sont pas exécutables avant l&#8217;arrivée aux modèles. Il est donc important de procéder à très petite itérations. Celle que je viens de prendre pour exemple est déjà presque trop longue (en fait, il est assez probable qu&#8217;en situation réelle, j&#8217;aurai d&#8217;abord fait le :show classique, puis j&#8217;aurais rajouté le :view_count).</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=424" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2010/01/21/le-developpement-top-down-en-uad/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Getters et setters en PHP</title>
		<link>http://blog.olivier-elmekki.com/2009/11/13/getters-et-setters-en-php/</link>
		<comments>http://blog.olivier-elmekki.com/2009/11/13/getters-et-setters-en-php/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 16:16:50 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=417</guid>
		<description><![CDATA[Venant du monde de ruby, j&#8217;ai pris l&#8217;habitude de ne pas faire de distinction dans l&#8217;utilisation d&#8217;un objet entre une méthode et un attribut. En ruby, un attribut se récupère exactement de la même manière qu&#8217;une méthode s&#8217;appelle.

Prenons le script suivant :

class Person
  attr_accessor :food
&#160;
  def initialize
    @food = 10
 [...]]]></description>
			<content:encoded><![CDATA[<p>Venant du monde de ruby, j&#8217;ai pris l&#8217;habitude de ne pas faire de distinction dans l&#8217;utilisation d&#8217;un objet entre une méthode et un attribut. En ruby, un attribut se récupère exactement de la même manière qu&#8217;une méthode s&#8217;appelle.<br />
<span id="more-417"></span></p>
<p>Prenons le script suivant :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Person
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:food</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize
    <span style="color:#0066ff; font-weight:bold;">@food</span> = <span style="color:#006666;">10</span>
    <span style="color:#0066ff; font-weight:bold;">@firstname</span> = <span style="color:#996600;">'John'</span>
    <span style="color:#0066ff; font-weight:bold;">@lastname</span>  = <span style="color:#996600;">'Doe'</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> eat
    <span style="color:#0066ff; font-weight:bold;">@food</span> <span style="color:#006600; font-weight:bold;">-</span>= <span style="color:#006666;">1</span>
    <span style="color:#0000FF; font-weight:bold;">true</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> name
    <span style="color:#0066ff; font-weight:bold;">@firstname</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">' '</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#0066ff; font-weight:bold;">@lastname</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> name=<span style="color:#006600; font-weight:bold;">&#40;</span> fullname <span style="color:#006600; font-weight:bold;">&#41;</span>
    parts      = fullname.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">' '</span>, <span style="color:#006666;">2</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@firstname</span> = parts<span style="color:#006600; font-weight:bold;">&#91;</span>0<span style="color:#006600; font-weight:bold;">&#93;</span>
    <span style="color:#0066ff; font-weight:bold;">@lastname</span>  = parts<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
michel = Person.<span style="color:#9900CC;">new</span>
michel.<span style="color:#9900CC;">name</span> = <span style="color:#996600;">'Michel Dupont'</span>
michel.<span style="color:#9900CC;">food</span>                     <span style="color:#008000; font-style:italic;"># =&gt; 10</span>
michel.<span style="color:#9900CC;">eat</span>                      <span style="color:#008000; font-style:italic;"># =&gt; true</span>
michel.<span style="color:#9900CC;">name</span>                     <span style="color:#008000; font-style:italic;"># =&gt; 'Michel Dupont'</span></pre></div></div>

<p>Nous voyons ici qu&#8217;il n&#8217;est pas possible de distinguer, formellement, la méthode &#8220;eat&#8221; et la méthode &#8220;name&#8221; de l&#8217;attribut &#8220;food&#8221;.  Que nous importe, finalement, leur implémentation? Lorsque j&#8217;utilise l&#8217;interface d&#8217;un objet, je veux soit exécuter une action, soit manipuler une valeur. Dans le cas où je souhaite retrouver une valeur, peu m&#8217;importe de savoir si cette valeur se trouve directement dans un attribut ou si une méthode est appelée pour me le retourner : cela relève de l&#8217;implémentation et non de l&#8217;usage. Au niveau de l&#8217;usage, ici, je sais que &#8220;food&#8221; et &#8220;name&#8221; me retourneront des valeurs, parce que ce sont des noms, et je sais que &#8220;eat&#8221; exécutera une action, parce que c&#8217;est un verbe.</p>
<p>Qu&#8217;en est-il en PHP? Le même script s&#8217;écrirait :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span> ?php
<span style="color: #000000; font-weight: bold;">class</span> Person 
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span>    <span style="color: #000088;">$food</span>;
  protected <span style="color: #000088;">$firstname</span>;
  protected <span style="color: #000088;">$lastname</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span>       <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span>  <span style="color: #339933;">=</span> <span style="">'John'</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>   <span style="color: #339933;">=</span> <span style="">'Doe'</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> eat<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span> <span style="color: #339933;">-=</span> <span style="color: #cc66cc;">1</span>;
    <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">true</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span> <span style="color: #339933;">.</span> <span style="">' '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setName<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$fullname</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$parts</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_split</span><span style="color: #009900;">&#40;</span> <span style="">'/ /'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fullname</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$parts</span><span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>  <span style="color: #339933;">=</span> <span style="color: #000088;">$parts</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span>;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$fullname</span>;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$michel</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Person<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setName</span><span style="color: #009900;">&#40;</span> <span style="">'Michel Dupont'</span> <span style="color: #009900;">&#41;</span>;   
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span>;                         <span style="color: #666666; font-style: italic;">// =&gt; 10</span>
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">eat</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;                        <span style="color: #666666; font-style: italic;">// =&gt; true</span>
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;                    <span style="color: #666666; font-style: italic;">// =&gt; 'Michel Dupont'</span></pre></div></div>

<p>Nous voyons ici que l&#8217;implémentation est clairement visible. &#8220;food&#8221; est un attribut, &#8220;eat&#8221;, &#8220;setName&#8221; et &#8220;getName&#8221; sont des méthodes. L&#8217;astuce, chez PHP, est de transformer un nom en verbe par l&#8217;emploi des setters et des getters ( setName() et getName() ) pour justifier l&#8217;appel d&#8217;une méthode. Néanmoins, rien ne justifie le fait que je doive exécuter une action sur une Person pour avoir son nom. Il s&#8217;agit d&#8217;une valeur et cela ne me regarde pas, à l&#8217;usage, de savoir comment ce nom a été retrouvé.</p>
<h3>Suggestion d&#8217;une implémentation</h3>
<p>Dans l&#8217;extension framework que j&#8217;ai faite pour Typolight, j&#8217;ai généralisé l&#8217;emploi d&#8217;un design différent pour répondre à ce problème. En voici un exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span> ?php
<span style="color: #000000; font-weight: bold;">class</span> Person 
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span>    <span style="color: #000088;">$food</span>;
  protected <span style="color: #000088;">$firstname</span>;
  protected <span style="color: #000088;">$lastname</span>;
  protected <span style="color: #000088;">$_cache</span>      <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
  protected <span style="color: #000088;">$_uncachable</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span>       <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span>  <span style="color: #339933;">=</span> <span style="">'John'</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>   <span style="color: #339933;">=</span> <span style="">'Doe'</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
&nbsp;
  <span style="color: #0000ff; font-style: italic;">/**
   * Check if a getter method exists
   *
   * @param string  the attribute name
   * @return mixed
   */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __get<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$firstLetter</span> <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$rest</span>        <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$getter</span>      <span style="color: #339933;">=</span> <span style="">'get'</span> <span style="color: #339933;">.</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$firstLetter</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$rest</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #990000;">method_exists</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #000088;">$getter</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cache <span style="color: #009900;">&#41;</span> and <span style="color: #339933;">!</span> <span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_uncachable <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cache<span style="color: #009900;">&#91;</span> <span style="color: #000088;">$key</span> <span style="color: #009900;">&#93;</span>;
      <span style="color: #009900;">&#125;</span>
&nbsp;
      <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$getter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> <span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_uncachable <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cache<span style="color: #009900;">&#91;</span> <span style="color: #000088;">$key</span> <span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span>;
      <span style="color: #009900;">&#125;</span>
&nbsp;
      <span style="color: #b1b100;">return</span> <span style="color: #000088;">$result</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    throw <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Unknown attribute&quot;</span> <span style="color: #009900;">&#41;</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
&nbsp;
  <span style="color: #0000ff; font-style: italic;">/**
   * Check if a setter method exists
   *
   * @param string  the attribute name
   * @param string  the attribute value
   * @return mixed
   */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __set<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$firstLetter</span>  <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$rest</span>         <span style="color: #339933;">=</span> <span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$setter</span>       <span style="color: #339933;">=</span> <span style="">'set'</span> <span style="color: #339933;">.</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$firstLetter</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$rest</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #990000;">method_exists</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #000088;">$setter</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cache<span style="color: #009900;">&#91;</span> <span style="color: #000088;">$key</span> <span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$setter</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$value</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">else</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$getter</span> <span style="color: #339933;">=</span> <span style="">'get'</span> <span style="color: #339933;">.</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$firstLetter</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$rest</span>;
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #990000;">method_exists</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #000088;">$getter</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cache<span style="color: #009900;">&#91;</span> <span style="color: #000088;">$key</span> <span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$value</span>;
        <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">true</span>;
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    throw <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Unknown attribute&quot;</span> <span style="color: #009900;">&#41;</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> eat<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span> <span style="color: #339933;">-=</span> <span style="color: #cc66cc;">1</span>;
    <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">true</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span> <span style="color: #339933;">.</span> <span style="">' '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setName<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$fullname</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$parts</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_split</span><span style="color: #009900;">&#40;</span> <span style="">'/ /'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fullname</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">firstname</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$parts</span><span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">lastname</span>  <span style="color: #339933;">=</span> <span style="color: #000088;">$parts</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span>;
    <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">true</span>;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">// Nous pouvons maintenant faire ceci :</span>
<span style="color: #000088;">$michel</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Person<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span> <span style="color: #339933;">=</span> <span style="">'Michel Dupont'</span>;  
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">food</span>;                    <span style="color: #666666; font-style: italic;">// =&gt; 10</span>
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">eat</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;                   <span style="color: #666666; font-style: italic;">// =&gt; true</span>
<span style="color: #000088;">$michel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span>;                    <span style="color: #666666; font-style: italic;">// =&gt; 'Michel Dupont'</span></pre></div></div>

<p>Ainsi, en utilisant les méthodes magiques __set() et __get(), nous pouvons rétablir le respect de la blackbox. Lorsque $michel->name est exécuté, __get() est appelé ( puisqu&#8217;il n&#8217;existe pas d&#8217;attribut $name ) et vérifie s&#8217;il existe une méthode getName().</p>
<p>En outre, cela permet d&#8217;ajouter un système de cache. La prochaine fois que j&#8217;appellerai $michel->name, la valeur précédente sera directement retournée plutôt que de devoir executer la méthode à nouveau. Si je veux éviter ce comportement, il me suffit d&#8217;appeler directement la méthode en faisant $michel->getName(), et le nom sera recalculé.</p>
<p>Bien entendu, mettre en place un tel mécanisme n&#8217;a pas de sens pour une petite classe isolée. J&#8217;ai employé personnellement ce mécanisme pour la couche modèle et la couche controller de mon extension. Cela est particulièrement intéressant pour les modèles, qui doivent se comporter de la manière la plus naturelle possible et qui font régulièrement des requêtes sur la base de donnée. Avec un tel mécanisme vous pouvez, dans le cadre d&#8217;un framework MVC, utiliser autant de fois que vous le voulez vos modèles dans vos vues de manière intuitive et sans vous soucier de savoir si cela va exécuter une requête sql ou non.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=417" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/11/13/getters-et-setters-en-php/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Typolight et les modèles : M comme dans VC</title>
		<link>http://blog.olivier-elmekki.com/2009/11/08/typolight-et-les-modeles-m-comme-dans-vc/</link>
		<comments>http://blog.olivier-elmekki.com/2009/11/08/typolight-et-les-modeles-m-comme-dans-vc/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 00:41:32 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[Non classé]]></category>

		<category><![CDATA[typolight]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=407</guid>
		<description><![CDATA[Si on me posait la question du problème majeur dans le core de Typolight, je répondrais : l&#8217;implémentation incomplète du pattern MVC. La couche modèle est difficilement utilisable telle-quelle et provoque l&#8217;abondance de requêtes SQL dans les contrôleurs. Il y a aussi le problème de la présence de HTML dans les contrôleurs, mais cela ne [...]]]></description>
			<content:encoded><![CDATA[<p>Si on me posait la question du problème majeur dans le core de Typolight, je répondrais : l&#8217;implémentation incomplète du pattern MVC. La couche modèle est difficilement utilisable telle-quelle et provoque l&#8217;abondance de requêtes SQL dans les contrôleurs. Il y a aussi le problème de la présence de HTML dans les contrôleurs, mais cela ne concernera pas ce tutoriel. Nous verrons cette fois comment rendre aux modèles ce qui appartient aux modèles.</p>
<p><span id="more-407"></span></p>
<h3>Le MVC, c&#8217;est quoi?</h3>
<p>Pour ceux qui ne sont pas familiers à la notion de <a href="http://fr.wikipedia.org/wiki/Modèle-Vue-Contrôleur">MVC</a>, récapitulons brièvement. MVC est un acronyme pour : Model, View, Controller ( en français, ça marche bien aussi ). Il s&#8217;agit d&#8217;un <a href="http://fr.wikipedia.org/wiki/Patron_de_conception">design pattern</a> qui structure une application selon trois tâches :</p>
<ul>
<li>Le traitement des données ( Modèles )</li>
<li>La présentation des données ( Vues )</li>
<li>La logique qui détermine quelles données associer à quelle présentation ( Contrôleurs )</li>
</ul>
<p>Typiquement, dans une application web, les modèles sont tous les calculs faits sur la base de donnée ; les vues sont les fichiers contenant le html ( ou autre, par exemple la structure d&#8217;un email ) ; les contrôleurs sont ce qui gèrent les requêtes ( POST, GET, etc ), leurs paramètres, et décident quels modèles utiliser et quelles variables fournir aux vues.</p>
<p>La couche modèle est en général gérée par un ORM ( <a href="http://fr.wikipedia.org/wiki/Mapping_objet-relationnel">Object Relational Mapping</a> ). Celui-ci permet de manipuler la base de donnée sans faire soi-même de pénibles requêtes SQL. Si par exemple j&#8217;ai dans ma base de donnée une table posts avec des champs id, name, content et author, j&#8217;aurai une classe Post, héritant de Model, qui me permettra de manipuler les entrées de la base de donnée comme des objets. Voici un exemple de PHP fictif qui illustre la manipulation d&#8217;un modèle :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// récupérer l'entrée de la tables posts qui à l'id 10</span>
<span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Post<span style="color: #339933;">::</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">10</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// retrouver son attribut &quot;name&quot;</span>
<span style="color: #990000;">echo</span> <span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// le modifier</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span> <span style="color: #339933;">=</span> <span style="">'an other name'</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// sauvegarder le changement dans la base de donnée</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// récupérer tous les posts dans un array</span>
<span style="color: #000088;">$posts</span> <span style="color: #339933;">=</span> Post<span style="color: #339933;">::</span><span style="color: #004000;">findAll</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>On peut ensuite utiliser ce array dans une vue, avec par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">&lt;ul id=&quot;posts&quot;&gt;
  &lt; ?php foreach ( $posts as $post ) : ?&gt;
  &lt;li&gt;&lt;a href=&quot;post-<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #990000;">echo</span> <span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">id</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;&lt; ?php echo $post-&gt;name ?&gt;&lt;/a&gt;, by &lt; ?php echo $post-&gt;author ?&gt;&lt;/li&gt;
  &lt; ?php endforeach ?&gt;
&lt;/ul&gt;</pre></div></div>

<p>Dans Typolight, les vues sont les templates et les contrôleurs sont les FrontendModule et BackendModule. Il n&#8217;y a malheureusement pas d&#8217;équivalence pour la couche modèle, et les données sont généralement retrouvées en remplissant les contrôleurs de requêtes SQL, ce qui rend la base de donnée pénible à utiliser et encombre les contrôleurs.</p>
<h3>Comment utiliser une couche modèle dans Typolight?</h3>
<p>Heureusement, une couche modèle existe belle et bien. Le fichier est TL_ROOT/system/libraries/Model.php . Ce fichier dispose des méthodes de base d&#8217;une couche modèle, mais il semble avoir été sabordé en route. En effet, c&#8217;est un <a href="ihttp://fr.wikipedia.org/wiki/Singleton_%28patron_de_conception%29">singleton</a> ( ce qui signifie qu&#8217;un seul objet de cette classe peut exister en même temps ). Il a en fait été pensé pour ne servir qu&#8217;aux classes User, BackendUser et FrontendUser, permettant de gérer l&#8217;utilisateur actuellement loggé.</p>
<p>Il n&#8217;y a en fait qu&#8217;une simple chose à faire pour rendre une couche modèle utilisable dans Typolight : créer une classe qui descend de Model et rendre publique sa méthode __construct(). C&#8217;est par exemple la méthode choisie par les développeurs de Isotope, ou par ma propre extension framework.</p>
<p>Nous allons reprendre la base du <a href="http://www.typolight.fr/forums/viewtopic.php?id=422">précédent tutoriel</a>. Nous avions deux tables SQL : tl_filiere_services et tl_filiere_filiales. Nous allons donc faire deux classes de modèles : Service et Filiale.</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span> ?php <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">defined</span><span style="color: #009900;">&#40;</span><span style="">'TL_ROOT'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="">'You can not access this file directly!'</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #0000ff; font-style: italic;">/**
 * TYPOlight webCMS
 * Copyright (C) 2005 Leo Feyer
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program. If not, please visit the Free
 * Software Foundation website at http://www.gnu.org/licenses/.
 *
 * PHP version 5
 * @copyright  
 * @author    
 * @package    
 * @license    
 * @filesource
 */</span>
&nbsp;
&nbsp;
<span style="color: #0000ff; font-style: italic;">/**
 * Class Service
 *
 * @copyright  
 * @author     
 * @package    Model
 */</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Service <span style="color: #000000; font-weight: bold;">extends</span> Model
<span style="color: #009900;">&#123;</span>
  protected <span style="color: #000088;">$strTable</span> <span style="color: #339933;">=</span> <span style="">'tl_filiere_services'</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</pre>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span> ?php <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">defined</span><span style="color: #009900;">&#40;</span><span style="">'TL_ROOT'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="">'You can not access this file directly!'</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #0000ff; font-style: italic;">/**
 * TYPOlight webCMS
 * Copyright (C) 2005 Leo Feyer
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program. If not, please visit the Free
 * Software Foundation website at http://www.gnu.org/licenses/.
 *
 * PHP version 5
 * @copyright  
 * @author    
 * @package    
 * @license    
 * @filesource
 */</span>
&nbsp;
&nbsp;
<span style="color: #0000ff; font-style: italic;">/**
 * Class Filiale
 *
 * @copyright  
 * @author     
 * @package    Model
 */</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Filiale <span style="color: #000000; font-weight: bold;">extends</span> Model
<span style="color: #009900;">&#123;</span>
  protected <span style="color: #000088;">$strTable</span> <span style="color: #339933;">=</span> <span style="">'tl_filiere_services'</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Et c&#8217;est tout. Nous disposons maintenant de tout ce qu&#8217;il faut pour trouver une entrée, récupérer la valeur de ses champs, enregistrer ses changements ou l&#8217;effacer. Par exemple :</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// crée un objet service</span>
<span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Service<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// retrouver l'entrée qui a l'id 10</span>
<span style="color: #000088;">$service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">findBy</span><span style="color: #009900;">&#40;</span> <span style="">'id, 10 );
&nbsp;
// retrouve l'</span>attribut <span style="">'name'</span>
<span style="color: #990000;">echo</span> <span style="color: #000088;">$service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// modifie l'attribut 'name'</span>
<span style="color: #000088;">$service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span> <span style="color: #339933;">=</span> <span style="">'new service'</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// enregistre les modifications dans la base de donnée</span>
<span style="color: #000088;">$service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// efface l'entrée</span>
<span style="color: #000088;">$service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>Nous pouvons maintenant manipuler simplement nos services et nos filiales sans avoir à écrire de fastidieuses requêtes SQL.</p>
<p>Mais ce n&#8217;est pas tout ce à quoi sert un modèle. Pour respecter le design pattern, il faut que toute manipulation de donnée soit faite dans le modèle. C&#8217;est son rôle, après tout. Dans le monde de Ruby on Rails, il y a même une devise : &#8220;thick models, thin controllers&#8221; ( modèles gros et contrôleurs minces ). L&#8217;idée est que puisque les modèles gèrent les données et que, précisément, un site est d&#8217;abord une question de données, c&#8217;est aux modèles de faire la majeure partie du travail. Il y a là un partie pris ( comme toujours avec rails ), vous en penserez ce que vous voudrez. Néanmoins, il reste exact que les manipulations des données doivent être opérées par les modèles. Reste a définir la limite entre &#8220;traitement des données&#8221; et &#8220;contrôle d&#8217;une requête&#8221; :)</p>
<p>Prenons un exemple concret. Les services de nos filiales ont un prix. Disons que ce prix est hors taxe. Il va me falloir, à un moment ou un autre, calculer le prix TTC pour un service. C&#8217;est ici typiquement une méthode qui doit résider dans le modèle Service. Comme nous sommes insouciants, nous allons considérer que les taxes sont fixes et que nous pouvons considérer qu&#8217;elles sont de 20% ( dans un cas réel, il faudrait rendre cette valeur configurable en backend ). Voici la méthode que nous allons rajouter dans la classe Service :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> ttc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$ttc</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">price</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">price</span> <span style="color: #339933;">*</span> <span style="color:#800080;">0.2</span> <span style="color: #009900;">&#41;</span>;
  <span style="color: #b1b100;">return</span> <span style="color: #000088;">$ttc</span>;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Désormais, dans le template qui affiche un service, nous n&#8217;aurons plus qu&#8217;à faire :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>p<span style="color: #339933;">&gt;</span>Prix TTC <span style="color: #339933;">:</span> <span style="color: #339933;">&lt;</span> ?php <span style="color: #990000;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">service</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ttc</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> ?<span style="color: #339933;">&gt;&lt;/</span>p<span style="color: #339933;">&gt;</span></pre></div></div>

<p>( nous verrons dans un prochain tutoriel comment passer des variables à un template ).</p>
<h3>Ce que la classe Model de Typolight ne permet pas</h3>
<p>Aujourd&#8217;hui, les ORM des frameworks permettent toutes sortes de raffinements, telle que les associations, les validations, finders et autres.</p>
<p>Nos filiales ont des services. Nous voudrions, avec un objet $filiale, pouvoir faire $filiale->services() pour avoir la liste des services de cette filiale. C&#8217;est ce que permettent de faire les associations, par le biais de relations ( has many, has one, belongs to, many to many&#8230; ).</p>
<p>Nous voudrions aussi empêcher d&#8217;enregistrer les modifications sur une filiale si l&#8217;adresse mail fournie n&#8217;est pas dans un format valide ( par exemple &#8220;1HD23s&#8221; ). C&#8217;est le rôle des validations ( elle sont présentes dans les widgets backend, dans Typolight, mais pas dans la couche modèle ). </p>
<p>Enfin, nous voudrions pouvoir, par exemple, trouver toutes les filiales enregistrées depuis moins d&#8217;un mois. Ou simplement trouver toutes les filiales. Ou trouver la première filiale qui se trouve à Lyon. C&#8217;est le rôle des finders.</p>
<p>Avec la couche modèle de Typolight, vous devrez écrire ces méthodes vous-même. Si vous désirez avoir une solution générique pour ces problèmes relativement courant, je vous invite à utiliser ma classe EModel : <a href="http://github.com/oelmekki/typolight_framework/blob/master/system/modules/framework/EModel.php">http://github.com/oelmekki/typolight_framework/blob/master/system/modules/framework/EModel.php</a> ( promis, la documentation arrive. Vous devrez pour l&#8217;instant lire le code ou me poser des questions pour comprendre comment s&#8217;en servir ).</p>
<p>Cela conclut mon article sur les modèles dans Typolight. Nous verrons ensuite les modules frontend.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=407" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/11/08/typolight-et-les-modeles-m-comme-dans-vc/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hadopi 2 : la loi, c&#8217;est moi.</title>
		<link>http://blog.olivier-elmekki.com/2009/10/23/hadopi-2-la-loi-cest-moi/</link>
		<comments>http://blog.olivier-elmekki.com/2009/10/23/hadopi-2-la-loi-cest-moi/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 00:17:25 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[éditoral]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=385</guid>
		<description><![CDATA[Hadopi version 2 a donc été approuvée par le conseil constitutionnel.
Pour rappel, ce même conseil avait rejeté une version précédente en faisant appel à l&#8217;article 11 de la déclaration des droits de l&#8217;homme de 1789, estimant qu&#8217;un filtrage du réseau nuisait à la liberté d&#8217;expression. En effet, Internet permet de communiquer et empêcher l&#8217;accès à [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.olivier-elmekki.com/wp-content/uploads/2009/10/judge_dredd_ver1.jpg"><img class="alignnone size-thumbnail wp-image-389" style="margin-left: 10px; float:right;" title="judge_dredd_ver1" src="http://blog.olivier-elmekki.com/wp-content/uploads/2009/10/judge_dredd_ver1-150x150.jpg" alt="" width="150" height="150" /></a>Hadopi version 2 a donc été approuvée par le conseil constitutionnel.</p>
<p>Pour rappel, ce même conseil avait rejeté une version précédente en faisant appel à <a href="http://www.assemblee-nationale.fr/histoire/dudh/1789.asp">l&#8217;article 11 de la déclaration des droits de l&#8217;homme de 1789</a>, estimant qu&#8217;un filtrage du réseau nuisait à la liberté d&#8217;expression. En effet, Internet permet de communiquer et empêcher l&#8217;accès à Internet revient à nuire à la « libre communication des pensées et des opinions ».</p>
<p><span id="more-385"></span></p>
<p>Le point contesté était qu&#8217;une privation de liberté ne pouvait se faire sans l&#8217;intervention d&#8217;un juge (comme c&#8217;est le cas par exemple pour une peine de prison).</p>
<p>Or la loi que vient d&#8217;approuver aujourd&#8217;hui le conseil constitutionnel valide la mise en place de procédures simplifiées. Qu&#8217;est-ce qu&#8217;une procédure simplifiée? Ce n&#8217;est pas une comparution immédiate, telle qu&#8217;elle existe déjà dans les cas les plus extrêmes, c&#8217;est bien pire : il s&#8217;agit d&#8217;un jugement &#8220;interne&#8221; et immédiat dans lequel la présence de l&#8217;accusé n&#8217;est pas nécessaire.</p>
<p>Judge Dredd, bienvenue en France.</p>
<p>Notons cependant, ce passage du <a href="http://www.assemblee-nationale.fr/13/rapports/r1841.asp">rapport des discussions</a> :</p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';"><strong>M. Christian Paul. </strong>Quelle désinvolture, monsieur le Rapporteur, dans votre présentation des choses ! Nous sommes tout autant que vous garants de la qualité de la loi et de la défense des libertés !</span></p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';">Notre amendement vise donc à supprimer le recours aux ordonnances pénales. Vous nous dites, madame la ministre, que l’avis du Conseil d’État ne mentionne pas les ordonnances pénales. Je vous crois bien sûr. Mais n’est-il pas un peu facile de vous prévaloir de cet avis quand il vous arrange, tout en refusant de nous donner connaissance de l’ensemble du document ?</span></p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';">Monsieur le rapporteur, en acceptant une procédure de masse, vous réduisez les droits de la défense et proposez une justice expéditive. Cela n’est pas supportable. L’ordonnance pénale est une procédure écrite et non <a href="http://fr.wikipedia.org/wiki/Principe_du_contradictoire_dans_les_proc%C3%A9dures_juridictionnelles_en_France">contradictoire</a> : l’auteur des faits n’est pas entendu par le juge.</span></p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';"><strong>Mme Martine Billard. </strong>Même argumentaire.</span></p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';"><strong>M. le rapporteur.</strong> Avis défavorable. L’ordonnance pénale est certes une procédure simplifiée, mais elle est assortie de toutes les garanties. La personne incriminée peut être entendue par le juge si elle le souhaite et demander à être jugée au cours d’une audience publique.</span></p>
<p style="text-align: justify;"><span style="font-size: 13pt; font-family: 'Times New Roman';"><em>La Commission <strong>rejette </strong>les deux amendements.</em></span></p>
<p style="text-align: justify;">Ainsi, si vous êtes un jour victime d&#8217;Hadopi, sachez que vous pouvez refuser la « procédure simplifiée » et exiger un procès loyal.</p>
<p style="text-align: justify;">Notons encore (tout de même) qu&#8217;il est bien habile de rejeter les soupçons de privation des droits fondamentaux sur les même juges qui subissent déjà des attaques en règle pour être assujettis au pouvoir exécutif, qui se met en même temps à l&#8217;écart des critiques constitutionnelles. Chapeau bas pour Machiavel.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=385" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/10/23/hadopi-2-la-loi-cest-moi/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mise en ligne de Stick&#8217;innov et framework Typolight</title>
		<link>http://blog.olivier-elmekki.com/2009/09/04/mise-en-ligne-de-stickinnov-et-framework-typolight/</link>
		<comments>http://blog.olivier-elmekki.com/2009/09/04/mise-en-ligne-de-stickinnov-et-framework-typolight/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 13:39:27 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[typolight]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=367</guid>
		<description><![CDATA[Stick&#8217;innov est une société de vente de stickers muraux, vous proposant les classiques stickers adhésifs et pochoirs, ainsi qu&#8217;un produit nouveau : le sticker magnétique. Celui-ci peut être choisi avec un support en laize magnétique ou en peinture aimantée. Un large catalogue vous permet de rajouter une touche personnelle corespondant aux différentes ambiences de votre [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.stick-innov.fr/accueil.html">Stick&#8217;innov</a> est une société de vente de stickers muraux, vous proposant les classiques stickers adhésifs et pochoirs, ainsi qu&#8217;un produit nouveau : le sticker magnétique. Celui-ci peut être choisi avec un support en <a href="http://www.stick-innov.fr/mode-demploi-stickers-magnetiques-support-vinyle-magnetique.html">laize magnétique</a> ou en <a href="http://www.stick-innov.fr/mode-demploi-stickers-magnetiques-support-peinture-aimantee.html">peinture aimantée</a>. Un large catalogue vous permet de rajouter une touche personnelle corespondant aux différentes ambiences de votre logement, pour <a href="http://www.stick-innov.fr/adhesif/Abstrait-35/modele/334.html">adoucir votre salon</a>, ajouter <a href="http://www.stick-innov.fr/adhesif/Nature-9/modele/111.html">une note exotique</a> ou créer la surprise au détour <a href="http://www.stick-innov.fr/adhesif/Panneaux-33/modele/380.html">d&#8217;une fantaisie</a>.</p>
<p><span id="more-367"></span></p>
<p>J&#8217;ai réalisé ce site avec <a href="http://www.bouctoubou.com/">Telly Delalande</a>, pour le compte de la société Stick&#8217;Innov. Telly s&#8217;est occupé de la charte graphique et de l&#8217;intégration et j&#8217;ai pris en charge le développement moteur et la couche javascript. Pour distinguer le site de ses concurents et lui offrir une avance en référencement, nous avons fait le choix de réaliser l&#8217;application sans utiliser  flash, au profit d&#8217;une interface javascript non obstrusive et dégradable.</p>
<p>Le site est realisé entièrement sous <a href="http://www.typolight.org/">Typolight</a>, autant pour les pages statiques, que pour les fonctions motrices et que pour la partie boutique. Il constitue une première démonstration publique de ce qui est faisable avec Typolight et mon extension framework. Cette application étant commerciale et réalisée pour un tiers, je ne peux en montrer le code, mais je peux démontrer certaines particularités du framework.</p>
<h3>Les routes</h3>
<p>Ce qui est peut-être le plus flagrant pour un utilisateur de Typolight est l&#8217;usage des routes. Prenons par exemple l&#8217;adresse : http://www.stick-innov.fr/adhesif/Abstrait-35/modele/105.html . Ceci est rendu possible en utilisant une &#8220;route&#8221;. Une route est caractérisée par une définition, reflétant l&#8217;url, qui lorsqu&#8217;elle correspond renvoie à une page donnée avec des paramètres donnés. Ces routes peuvent être configurées soit dans le config/config.php de votre module, soit en backend. Ici, je l&#8217;ai mise dans le config.php, ce qui donne :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">array_insert<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$GLOBALS</span><span style="color: #009900;">&#91;</span> <span style="">'TL_ROUTES'</span> <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">&quot;fr_adhesif&quot;</span>          <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="">'route'</span>         <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif/:theme/modele/:modele_id'</span><span style="color: #339933;">,</span>
      <span style="">'staticParams'</span>  <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="">'action'</span> <span style="color: #339933;">=&amp;</span>gt; <span style="">'index'</span><span style="color: #339933;">,</span>
        <span style="">'type'</span>   <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="">'method'</span>    <span style="color: #339933;">=&amp;</span>gt; <span style="">'GET'</span><span style="color: #339933;">,</span>
      <span style="">'resolveTo'</span>     <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>La définition de la route est donc ici : &#8216;adhesif/:theme/modele/:modele_id&#8217;. :theme et :modele_id sont des variables. N&#8217;importe quelle valeur peut y être introduite et sera injectée dans les paramètres GET, récupérable avec $this-&gt;Input-&gt;get( &#8216;nom_du_param&#8217; ).</p>
<p>L&#8217;option &#8217;staticParams&#8217; permet de rajouter arbitrairement des paramètres supplémentaires. Ici, &#8216;action&#8217; est utilisé pour déterminer quelle action le contrôleur devra executer et &#8216;type&#8217; est un paramètre que j&#8217;ai ajouté pour pouvoir ne faire qu&#8217;un contrôleur pour les trois types de produits.</p>
<p>L&#8217;option &#8216;method&#8217; détermine quel verbe http accepte la route. En utilisant GET, nous interdisons l&#8217;usage de POST. Si nous utilisons un POST sur cette url, l&#8217;application répondra par une 404. Cela permet de router vers des actions ou pages différentes le GET et le POST sur une même url. Les options de &#8216;method&#8217; sont : &#8216;GET&#8217;, &#8216;POST&#8217; ou &#8216;GET/POST&#8217;. Ce dernier accepte les deux verbes.</p>
<p>Enfin, l&#8217;option &#8216;resolveTo&#8217; indique la page vers laquelle la route redirige.</p>
<p>Cette route a un nom : &#8216;fr_adhesif&#8217;. Ce nom est utilisé pour générer une url à partir d&#8217;un nom, grâce à Route::compose(). Ainsi, si nous avons :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">array_insert<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$GLOBALS</span><span style="color: #009900;">&#91;</span> <span style="">'TL_ROUTES'</span> <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">&quot;product_list&quot;</span>          <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="">'route'</span>         <span style="color: #339933;">=&amp;</span>gt; <span style="">'voir/les/produits'</span><span style="color: #339933;">,</span>
      <span style="">'staticParams'</span>  <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="">'action'</span> <span style="color: #339933;">=&amp;</span>gt; <span style="">'list'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="">'method'</span>    <span style="color: #339933;">=&amp;</span>gt; <span style="">'GET'</span><span style="color: #339933;">,</span>
      <span style="">'resolveTo'</span>     <span style="color: #339933;">=&amp;</span>gt; <span style="">'produits'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>et que nous voulons faire un lien en utilisant cette route dans une vue, nous pouvons faire :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>a href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;&amp;lt;?php echo Route::compose( 'product_list' ) ?&amp;gt;&quot;</span><span style="color: #339933;">&gt;</span>Voir les produits<span style="color: #339933;">&lt;/</span>a<span style="color: #339933;">&gt;</span></pre></div></div>

<p>ou, avec un insert tag :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>a href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;{{Route::product_list}}&quot;</span><span style="color: #339933;">&gt;</span>Voir les produits<span style="color: #339933;">&lt;/</span>a<span style="color: #339933;">&gt;</span></pre></div></div>

<p>Il est ensuite possible de modifier la définition de la route sans avoir à modifier ce code.</p>
<p>Dans le cas de la première route que j&#8217;ai montrée, il y a également deux paramètres dynamiques, :theme et :modele_id. Ces paramètres sont ajoutés en passant un array associatif :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>a href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;&amp;lt;?php echo Route::compose( 'fr_adhesif', array( 'theme' =&amp;gt; $theme-&amp;gt;urlName, 'modele_id' =&amp;gt; $modele-&amp;gt;id ) ) ?&amp;gt;&quot;</span><span style="color: #339933;">&gt;</span>Voir les produits<span style="color: #339933;">&lt;/</span>a<span style="color: #339933;">&gt;</span></pre></div></div>

<p>Enfin, les routes supportent l&#8217;internationalisation. Si nous avons :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">array_insert<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$GLOBALS</span><span style="color: #009900;">&#91;</span> <span style="">'TL_ROUTES'</span> <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">&quot;fr_adhesif&quot;</span>          <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="">'route'</span>         <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif/:theme/modele/:modele_id'</span><span style="color: #339933;">,</span>
      <span style="">'staticParams'</span>  <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="">'action'</span> <span style="color: #339933;">=&amp;</span>gt; <span style="">'index'</span><span style="color: #339933;">,</span>
        <span style="">'type'</span>   <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="">'method'</span>    <span style="color: #339933;">=&amp;</span>gt; <span style="">'GET'</span><span style="color: #339933;">,</span>
      <span style="">'resolveTo'</span>     <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">&quot;en_adhesif&quot;</span>          <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="">'route'</span>         <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesive/:theme/model/:modele_id'</span><span style="color: #339933;">,</span>
      <span style="">'staticParams'</span>  <span style="color: #339933;">=&amp;</span>gt; <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="">'action'</span> <span style="color: #339933;">=&amp;</span>gt; <span style="">'index'</span><span style="color: #339933;">,</span>
        <span style="">'type'</span>   <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="">'method'</span>    <span style="color: #339933;">=&amp;</span>gt; <span style="">'GET'</span><span style="color: #339933;">,</span>
      <span style="">'resolveTo'</span>     <span style="color: #339933;">=&amp;</span>gt; <span style="">'adhesif'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>nous pouvons utiliser :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>a href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;&amp;lt;?php echo Route::composeI18n( 'adhesif', array( 'theme' =&amp;gt; $theme-&amp;gt;urlName, 'modele_id' =&amp;gt; $modele-&amp;gt;id ) ) ?&amp;gt;&quot;</span><span style="color: #339933;">&gt;</span>Voir les produits<span style="color: #339933;">&lt;/</span>a<span style="color: #339933;">&gt;</span></pre></div></div>

<p>La langue courante sera utilisée pour déterminer quelle route il faut suivre.</p>
<p>Un dernier point : l&#8217;ordre des routes importe. Il est possible d&#8217;avoir des urls auxquelles plusieurs routes correspondent, comme par exemple si on a &#8220;voir/produits/tous&#8221; et &#8220;voir/produits/:produit_id&#8221;. Si cela arrive, la première route rencontrée l&#8217;emportera.</p>
<h3>Les contrôleurs</h3>
<p>Les contrôleurs de Typolight ( ModuleQuelqueChose, héritant de FrontendModule ) sont pensés pour n&#8217;executer qu&#8217;une seule action, bien qu&#8217;il soit possible de les forcer. Il y a la méthode generate() qui sert à initialiser le module, et la méthode compile() qui passe les variables à la vue ( template, dans le vocabulaire Typolight ). L&#8217;extension framework rajoute une nouvelle classe : RoutedModule.</p>
<p>RoutedModule est pensé pour permettre de gérer facilement des actions multiples. Quand un RoutedModule est généré, il regarde s&#8217;il existe un paramètre GET &#8216;action&#8217;. S&#8217;il y en a un et qu&#8217;une méthode du même nom existe dans le module, celle-ci est appelée et la vue est automatiquement déclarée selon le schémas : &#8216;fe&#8217; + nom du contrôleur + &#8216;_&#8217; + nom de l&#8217;action. Sinon, la méthode index() est utilisée. Prenons l&#8217;exemple d&#8217;un contrôleur simple :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;"><span style="color: #339933;">&amp;</span>lt; ?php
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> ControllerProduct <span style="color: #000000; font-weight: bold;">extends</span> RoutedModule
<span style="color: #009900;">&#123;</span>
  protected <span style="color: #000088;">$controller</span> <span style="color: #339933;">=</span> <span style="">'products'</span>;
&nbsp;
  <span style="color: #666666; font-style: italic;">/* List products */</span>
  protected <span style="color: #000000; font-weight: bold;">function</span> index<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;products <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;all;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">/* Show a product */</span>
  protected <span style="color: #000000; font-weight: bold;">function</span> show<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Input<span style="color: #339933;">-&amp;</span>gt;get<span style="color: #009900;">&#40;</span> <span style="">'product_id'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;product <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">/* Create a new product */</span>
  protected <span style="color: #000000; font-weight: bold;">function</span> create<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$success</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$posted</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Input<span style="color: #339933;">-&amp;</span>gt;post<span style="color: #009900;">&#40;</span> <span style="">'product'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;data <span style="color: #339933;">=</span> <span style="color: #000088;">$posted</span>;
&nbsp;
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$success</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">true</span>;
      <span style="color: #009900;">&#125;</span>
&nbsp;
      <span style="color: #b1b100;">else</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;errors <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;errors;
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;product <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;success <span style="color: #339933;">=</span> <span style="color: #000088;">$success</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">/* Update a product */</span>
  protected <span style="color: #000000; font-weight: bold;">function</span> update<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Input<span style="color: #339933;">-&amp;</span>gt;get<span style="color: #009900;">&#40;</span> <span style="">'product_id'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #000088;">$success</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$posted</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Input<span style="color: #339933;">-&amp;</span>gt;post<span style="color: #009900;">&#40;</span> <span style="">'product'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;update_attributes<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$posted</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$success</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">true</span>;
      <span style="color: #009900;">&#125;</span>
&nbsp;
      <span style="color: #b1b100;">else</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;errors <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;errors;
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;product <span style="color: #339933;">=</span> <span style="color: #000088;">$product</span>;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Template<span style="color: #339933;">-&amp;</span>gt;success <span style="color: #339933;">=</span> <span style="color: #000088;">$success</span>;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">/* Delete a product */</span>
  protected <span style="color: #000000; font-weight: bold;">function</span> delete<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;Input<span style="color: #339933;">-&amp;</span>gt;get<span style="color: #009900;">&#40;</span> <span style="">'product_id'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt;delete<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt;redirect<span style="color: #009900;">&#40;</span> Route<span style="color: #339933;">::</span><span style="color: #004000;">compose</span><span style="color: #009900;">&#40;</span> <span style="">'product_list'</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ceux qui se sont déjà servi de Ruby on Rails trouveront ici une note familière. Un utilisateur de Typolight pourra s&#8217;interroger sur les méthodes de Product. Product hérite en fait d&#8217;une autre classe du framework, EModel, que je traiterai une autre fois.</p>
<p>La première chose à faire est de donner un nom au contrôleur :</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">protected <span style="color: #000088;">$controller</span> <span style="color: #339933;">=</span> <span style="">'products'</span>;</pre></div></div>

<p>Ensuite, on définit les différentes actions, et le paramètre GET &#8216;action&#8217; déterminera lequel utiliser. La vue est automatiquement retrouvée d&#8217;après le nom du contrôleur et de l&#8217;action, comme je l&#8217;ai expliqué plus haut. Ici, on aura donc les vues : fe_products_index.tpl, fe_products_show.tpl, fe_products_create.tpl, fe_products_update.tpl et fe_products_delete.tpl .</p>
<p>RoutedModule offre de nombreuses autres fonctionalités, comme la possibilité de forcer l&#8217;action sans prendre en compte le paramètre d&#8217;action ( utile lorsqu&#8217;on a plusieurs RoutedModule dans une même page ), les getters et les setters, le cache, la gestion de json, et autres.</p>
<p>Si vous désirez essayer l&#8217;extension framework, vous pouvez la <a href="http://github.com/oelmekki/typolight_framework/tree/master">télécharger sur github</a>. Je suis sur le point de publier mon troisième site l&#8217;utilisant et je le considère donc comme stable. La version 1.0 devrait sortir sous peu, après un cleanup de l&#8217;API et l&#8217;écriture de documentation.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=367" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/09/04/mise-en-ligne-de-stickinnov-et-framework-typolight/feed/</wfw:commentRss>
		</item>
		<item>
		<title>CMS ou Framework? Le choix de Typolight</title>
		<link>http://blog.olivier-elmekki.com/2009/08/16/cms-ou-framework-le-choix-de-typolight/</link>
		<comments>http://blog.olivier-elmekki.com/2009/08/16/cms-ou-framework-le-choix-de-typolight/#comments</comments>
		<pubDate>Sun, 16 Aug 2009 12:03:02 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[typolight]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=359</guid>
		<description><![CDATA[La question est vieille, même si les développeurs refusent de se la poser clairement. Autant le dire tout de suite, j&#8217;ai moi aussi été un développeur qui ne voulait pas entendre parler de CMS. Les CMS, c&#8217;est bons pour les intégrateurs qui n&#8217;ont pas de dév, ça ne permet que de répondre aux besoins les [...]]]></description>
			<content:encoded><![CDATA[<p>La question est vieille, même si les développeurs refusent de se la poser clairement. Autant le dire tout de suite, j&#8217;ai moi aussi été un développeur qui ne voulait pas entendre parler de CMS. Les CMS, c&#8217;est bons pour les intégrateurs qui n&#8217;ont pas de dév, ça ne permet que de répondre aux besoins les plus courants en rendant toute extension pénible et tortueuse, c&#8217;est souvent mal écrit, tout ça.</p>
<p><span id="more-359"></span></p>
<h3>Premier contact avec Typolight</h3>
<p>Lorsque j&#8217;ai commencé mes activités de freelance, j&#8217;ai rencontré <a href="http://www.bouctoubou.com/">Telly Delalande</a>, avec lequel je travaille régulièrement aujourd&#8217;hui. Telly est passionné par un CMS qui s&#8217;appelle <a href="http://www.typolight.org/">Typolight</a>, et dont il m&#8217;a assuré que c&#8217;était <a href="http://blog.bouctoubou.com/typolight-le-meilleur-cms-au-monde/">le meilleur CMS du monde</a>. Son article a provoqué de telles réactions que j&#8217;ai décidé de lancer un troll moi aussi :)</p>
<p>Plus sérieusement, quand Telly m&#8217;a parlé de Typolight, j&#8217;ai accepté d&#8217;y jeter un oeil sans trop y croire. Premier constat : <a href="http://dev.typolight.org/wiki/DevelopmentIndex">la documentation pour développeur</a> est franchement lacunaire. Ok, qu&#8217;à cela ne tienne, &#8220;use the source, Luke&#8221;. J&#8217;ouvre le code pour essayer de comprendre comment tout cela fonctionne. Et là survient la première surprise : c&#8217;est bien codé, très bien codé, même. Il y a bien quelques vieilleries PHP-iennes, comme l&#8217;absence d&#8217;une vraie classe modèle ( la classe Model est un singleton destiné à mapper l&#8217;user courant ) et donc la profusion de requêtes sql dans les contrôleurs, mais le tout est propre est agréable à lire (sauf quelques fichiers plus anciens que les autres).</p>
<p>Je décide donc de faire un essai, et de mettre l&#8217;extensibilité à l&#8217;épreuve.</p>
<h3>Les modules</h3>
<p>L&#8217;extension de Typolight se fait comme dans beaucoup de CMS par l&#8217;ajout de modules. C&#8217;est donc assez banal, mais ça m&#8217;a plu sur le coup comme je venais juste d&#8217;essayer <a href="http://www.merbivore.com/">Merb</a> dont le concept de modulabilité m&#8217;avait beaucoup intéressé ( oui, ca se fait très bien par l&#8217;intermédiaire des plugins dans Rails ou Symfony, mais permettre quelque chose et encourager son utilisation dans le design même d&#8217;une application sont deux choses aux résultats totalement différents ).</p>
<p>Les modules de Typolight sont donc des répertoires, placés dans system/modules/, et dans lesquels on peut mettre tous les fichiers nécessaires à une fonctionalité : modèles, contrôleurs, vues, css, js, fichier de migration db, fichier de configuration, etc.</p>
<p>Tout de suite, les limitations apparaissent. Un contrôleur dans un module ne gère qu&#8217;une seule action. Cependant, l&#8217;application étant entièrement orientée objet et pensée pour la surcharge, il m&#8217;a été facile de rajouter un classe de contrôleur permettant de gérer plusieurs actions. Tout comme il m&#8217;a été possible de rajouter une gestion de routes complètement arbitraire. Tout comme il m&#8217;a été possible de rajouter un classe que j&#8217;ai nommée EModel, et qui reprend les fonctionnalités classiques d&#8217;un modèle dans les frameworks : associations, validations, recherches selon paramètres, etc. Les bases étaient posées.</p>
<h3>Utiliser Typolight comme un framework</h3>
<p>Au fur et à mesure que mes besoins se précisaient, je rajoutais des fonctionnalités dans mon module &#8220;<a href="http://github.com/oelmekki/typolight_framework/tree/master">framework</a>&#8221; qui me permettait de développer d&#8217;autres modules sans sentir de contraites CMS-iennes. Chaque fois, j&#8217;étais surpris d&#8217;avec quelle facilité c&#8217;était faisable. Bien sûr, il faut parcourir le code et le connaître un minimum dans son ensemble pour se permettre des modifications aussi conséquentes, mais c&#8217;est chaque fois la même surprise : c&#8217;est possible, et proprement en plus.</p>
<p>Aujourd&#8217;hui, j&#8217;utilise Typolight d&#8217;une manière très similaire à mon utilisation de Ruby on Rails. J&#8217;ai intégré <a href="http://cukes.info/">cucumber</a> et <a href="http://www.phpspec.org/">phpspec</a> par l&#8217;intermédiaire d&#8217;un module &#8220;<a href="http://github.com/oelmekki/typolight_testing/tree/master">testing</a>&#8220;, je fais donc du <a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development">bdd</a>, à base de user stories suivant lesquelles je déroule mes vues, contrôleurs, modèles et routes dans un soucis de réutilisabilité.</p>
<p>Je me retrouve donc dans la situation où l&#8217;argument de manque d&#8217;extensibilité est brisé.</p>
<h3>Focus!</h3>
<p>Dans le même mouvement, je me retrouve avec une pluvalue d&#8217;avantages qui relève de tous les inconvénients du framework quand on le compare au CMS : pas de perte de temps à coder des fonctionnalités banales que je ferai de toutes façons moins complètes que celles présentes dans un CMS, développées depuis des années.</p>
<p>C&#8217;est là qu&#8217;apparaît le point vraiment intéressant : le fait de pouvoir se permettre de se focaliser entièrement et uniquement sur les fonctionnalités spécifiques dont a besoin le client. Cela rend le développement rapide, beaucoup plus rapide. Recoupé avec la possibilité de faire du bdd, cela permet de produire des applications complètes, stables et peu coûteuses.</p>
<h3>CMS ou framework? Les deux mon capitaine.</h3>
<p>Cela m&#8217;amène à me poser la question : en quoi les CMS et les frameworks sont incompatibles? Les développeurs condamnent régulièrement les CMS pour leur manque d&#8217;extensibilité, mais il ne s&#8217;agit pas là d&#8217;une fatalité. C&#8217;est simplement un fait courant. Pour ma part, je dirais que le problème est surtout que beaucoup de CMS ont une base largement impérative, avec des require partout, l&#8217;OO n&#8217;apparaissant que dans la couche intermédiaire de l&#8217;application.</p>
<p>Un CMS pensé proprement (la notion de propreté voulant surtout dénoter la conformité aux bonnes pratiques du jour) peut très bien être extensible et peut même être pensé comme un framework.</p>
<p>Je n&#8217;irai pas dire que Typolight est ce CMS de rêve, mais il s&#8217;en rapproche incroyablement plus que les CMS dont nous avons l&#8217;habitude. Il rend en tous cas concrètement possible la fusion entre CMS et framework.</p>
<p>Peut-être est-ce à nous, développeurs, de proposer aujourd&#8217;hui des solutions CMS/Framework qui garantissent à la fois la possibilité d&#8217;être utilisées par des non-développeurs, de mettre en place en quelques minutes les fonctionnalités courantes, et d&#8217;offrir une extensibilité complète.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=359" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/08/16/cms-ou-framework-le-choix-de-typolight/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Datamith, convertisseur de base de donnée</title>
		<link>http://blog.olivier-elmekki.com/2009/02/14/datamith-convertisseur-de-base-de-donnee/</link>
		<comments>http://blog.olivier-elmekki.com/2009/02/14/datamith-convertisseur-de-base-de-donnee/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 21:58:16 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=354</guid>
		<description><![CDATA[Je viens de publier Datamith, un framework ruby permettant de convertir des base de données MySQL.
L&#8217;idée est de permettre de définir des règles de conversion pour importer le contenu d&#8217;une base de données dans une autre.

Dans son utilisation la plus simple, vous pouvez définir un ensemble de règle traduisant une base de donnée dans une [...]]]></description>
			<content:encoded><![CDATA[<p>Je viens de publier <a href="http://olivier-elmekki.com/datamith-fr.html">Datamith</a>, un framework ruby permettant de convertir des base de données MySQL.</p>
<p>L&#8217;idée est de permettre de définir des règles de conversion pour importer le contenu d&#8217;une base de données dans une autre.</p>
<p><span id="more-354"></span></p>
<p>Dans son utilisation la plus simple, vous pouvez définir un ensemble de règle traduisant une base de donnée dans une autre, par exemple pour changer de moteur de blog ou encore pour faire passer les données d&#8217;une application externe dans un module de CMS.</p>
<p>Il est également possible de s&#8217;en servir pour synchroniser une base de donnée. Si les entrées de la base de donnée source ont une clef primaire dont la valeur existe déjà dans la base de donnée de destination, les donnée de cette seconde base de donnée seront mis à jour (en suivant les règles définies).</p>
<p>Enfin, et c&#8217;est peut-être le plus intéressant, le framework peut être utilisé pour fusionner des bases de données. Imaginez que vous avez deux applications qui ont fait leur vie chacune de leur côté. Vous aimeriez importer les utilisateurs de l&#8217;une dans l&#8217;autre, mais il existe déjà des utilisateurs qui ont le même id. Datamith vous permet d&#8217;insérer ces utilisateurs tout en préservant les associations (par exemple le champs user_id de la table post).</p>
<p>Pour en savoir plus, je vous invite à voir <a href="http://olivier-elmekki.com/datamith-fr.html">la page de Datamith</a>, ainsi que sa <a href="http://olivier-elmekki.com/datamith/">documentation</a>. Le code est <a href="http://github.com/oelmekki/datamith/tree/master">téléchargeable sur Github</a>.</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=354" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/02/14/datamith-convertisseur-de-base-de-donnee/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Débugger les événements js avec firebugUJS</title>
		<link>http://blog.olivier-elmekki.com/2009/01/25/debugger-les-evenements-js-avec-firebugujs/</link>
		<comments>http://blog.olivier-elmekki.com/2009/01/25/debugger-les-evenements-js-avec-firebugujs/#comments</comments>
		<pubDate>Sun, 25 Jan 2009 16:07:39 +0000</pubDate>
		<dc:creator>kik</dc:creator>
		
		<category><![CDATA[javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://blog.olivier-elmekki.com/?p=346</guid>
		<description><![CDATA[Avec le retour en force de javascript, la quête des &#8220;bonne pratiques&#8221; a trouvé un nouveau lieu d&#8217;investigation. Elle y a pris un nom : UJS (unobstrusive javascript).

Cette tendance conseille de faire une distinction nette entre le javascript et le HTML (comme on distingue le CSS du HTML) et de ne voir en javascript qu&#8217;un [...]]]></description>
			<content:encoded><![CDATA[<p>Avec le retour en force de javascript, la quête des &#8220;bonne pratiques&#8221; a trouvé un nouveau lieu d&#8217;investigation. Elle y a pris un nom : <a href="http://fr.wikipedia.org/wiki/Javascript_discret">UJS</a> (unobstrusive javascript).</p>
<p><span id="more-346"></span></p>
<p>Cette tendance conseille de faire une distinction nette entre le javascript et le HTML (comme on distingue le CSS du HTML) et de ne voir en javascript qu&#8217;un &#8220;bonus&#8221;, ne perturbant pas l&#8217;utilisation du site si javascript venait à être désactivé par le navigateur.</p>
<p>Concrètement, cela passe par un développement de l&#8217;application excluant javascript, puis par l&#8217;implémentation d&#8217;une surcouche comportementale (animations, événements) dans un fichier javascript externe.</p>
<p>Il est donc exclu d&#8217;inclure de larges portions de javascript dans une balise script du HTML ou de définir dans les balises des attributs d&#8217;événements, comme onclick ou onmouseover.</p>
<h3>Le problème</h3>
<p>Si je veux exécuter la fonction <em>name_clicked()</em> lorsque je clique sur le <em>li</em> avec la classe <em>name</em>, je ferai ainsi avec jQuery :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">'li.name'</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> name_clicked<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>Le problème ici est que je ne disposerai d&#8217;aucun moyen pour savoir si l&#8217;événement à bien été attaché à un <em>li</em> en particulier. Si je clique sur le <em>li</em> et que rien ne se passe, est-ce un problème avec <em>name_clicked()</em> ou avec l&#8217;événement? Le seul moyen que j&#8217;ai de vérifier est de parsemer mon code de <em>alert()</em> ou de <em>console.log()</em>, ce qui est généralement la solution de dernier recours.</p>
<h3>La solution</h3>
<p><a href="http://remi.org/">Ryan Taylor</a> a publié <a href="http://remi.org/2009/01/06/using-firebug-to-debug-unobtrusive-javascript.html">au début du mois</a> une extension pour firebug qui permet de lister les événements ajoutés à un élément du DOM : <a href="http://github.com/remi/firebug-ujs/tree/master">firebugUJS</a>.</p>
<p>Son fonctionnement est simple : vous inspectez un élément comme d&#8217;habitude et vous choisissez dans la fenêtre de l&#8217;inspecteur de styles du menu HTML l&#8217;onglet <em>Events. </em>Le code du callback de l&#8217;événement y est alors présenté.</p>
<p><img src="/wp-content/uploads/2009/01/screen.jpg" alt="screenshot firebugUJS" /></p>
<h3>Limitations</h3>
<p>L&#8217;extension est encore à ses débuts de développement. Elle ne supporte pour l&#8217;instant principalement que <a href="http://jquery.com/">jQuery</a> et <a href="http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype">LowPro</a> (un effort pour rendre Prototype moins obstrusif).</p>
<p>Après une semaine d&#8217;essai, j&#8217;en suis relativement satisfait (relativement, parce que c&#8217;est donc un début et que je passe les problèmes pour cette raison). Cette extension m&#8217;a déjà permis de gagner du temps, mais il y a encore quelques petites choses à corriger. En particulier, les événements n&#8217;apparaissent parfois pas (il faut recharger la page une seconde fois), une quantité importante d&#8217;informations plus utiles au développeur de l&#8217;extension qu&#8217;à moi apparaissent dans la partie console de firebug (ce qui est tout à fait excusable) et surtout : il m&#8217;est déjà arrivé deux fois de devoir désactiver l&#8217;extension parce qu&#8217;elle faisait planter une application qui utilisait lourdement javascript (piwik la première fois, l&#8217;ajout d&#8217;image dans wordpress la seconde fois).</p>
<p>Malgré cela, je continue d&#8217;utiliser cette extension car je fais un usage intensif des événements js et qu&#8217;elle m&#8217;a déjà permis de gagner beaucoup de temps. Si ce n&#8217;est pas votre cas, vous voudrez probablement attendre une version plus stable.</p>
<p>Une affaire à suivre, donc :)</p>
 <img src="http://blog.olivier-elmekki.com/wp-content/plugins/feed-statistics.php?view=1&post_id=346" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.olivier-elmekki.com/2009/01/25/debugger-les-evenements-js-avec-firebugujs/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

