<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DevOrigin - Le blog</title>
	<atom:link href="http://blog.devorigin.fr/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.devorigin.fr</link>
	<description>Symfony et le reste</description>
	<lastBuildDate>Thu, 03 Sep 2009 08:57:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sauvegarde Time Machine échoue &#8230;</title>
		<link>http://blog.devorigin.fr/mac/sauvegarde-time-machine-echoue-103</link>
		<comments>http://blog.devorigin.fr/mac/sauvegarde-time-machine-echoue-103#comments</comments>
		<pubDate>Thu, 03 Sep 2009 08:57:27 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[snow leopard]]></category>
		<category><![CDATA[time machine]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=103</guid>
		<description><![CDATA[Tout récent possesseur d'un disque externe USB Buffalo MiniStation Lite de 500 Go, j'ai voulu m'en servir comme disque de sauvegarde Time Machine. Malheureusement la sauvegarde échoue à chaque fois ... un problème tout bête à résoudr]]></description>
			<content:encoded><![CDATA[<p>Tout récent possesseur d&#8217;un disque externe USB Buffalo MiniStation Lite de 500 Go, j&#8217;ai voulu m&#8217;en servir comme disque de sauvegarde Time Machine. Malheureusement la sauvegarde échoue à chaque fois &#8230; un problème tout bête à résoudre.</p>
<p>J&#8217;ai mis un peu de temps à trouver d&#8217;où venait le souci. C&#8217;est en fait spotlight qui par défaut indexe le disque de sauvegarde. Ce disque externe n&#8217;a qu&#8217;un câble pour l&#8217;alimentation et pour les données. Donc à mon avis la sauvegarde Time Machine de 90Go plus l&#8217;indexation spotlight du disque en même temps ça faisait un peu trop. J&#8217;ai juste eu à désactiver l&#8217;indexation du disque dans les préférences de spotlight, et Time Machine n&#8217;échoue plus à faire la sauvegarde &#8230;</p>
<p>Voilà si ça peut aider certaines personnes <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/mac/sauvegarde-time-machine-echoue-103/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Compiler libsdl avec MacPorts sous Snow Leopard</title>
		<link>http://blog.devorigin.fr/logiciel/compiler-libsdl-avec-macports-sous-snow-leopard-93</link>
		<comments>http://blog.devorigin.fr/logiciel/compiler-libsdl-avec-macports-sous-snow-leopard-93#comments</comments>
		<pubDate>Tue, 01 Sep 2009 11:11:32 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Ligne de commande]]></category>
		<category><![CDATA[Logiciel]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[compilation]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=93</guid>
		<description><![CDATA[Comme j&#8217;ai eu le souci (notamment pour faire marcher wxWidgets) je vous fais part de la solution  

---&#62;  Building libsdl
Error: Target org.macports.build returned: shell command &#34; cd &#34;/opt/local/var...work/SDL-1.2.13&#34; &#38;&#38; /usr/bin/make -j2 all &#34; returned error 2
Command output: ./src/video/quartz/SDL_QuartzEvents.m:691: error: 'struct SDL_PrivateVideoData' has no member named 'power_connection'
./src/video/quartz/SDL_QuartzEvents.m: In function 'QZ_PumpEvents':
./src/video/quartz/SDL_QuartzEvents.m:737: error: 'UsrActivity' undeclared (first [...]]]></description>
			<content:encoded><![CDATA[<p>Comme j&#8217;ai eu le souci (notamment pour faire marcher wxWidgets) je vous fais part de la solution <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<pre class="brush: plain;">
---&gt;  Building libsdl
Error: Target org.macports.build returned: shell command &quot; cd &quot;/opt/local/var...work/SDL-1.2.13&quot; &amp;&amp; /usr/bin/make -j2 all &quot; returned error 2
Command output: ./src/video/quartz/SDL_QuartzEvents.m:691: error: 'struct SDL_PrivateVideoData' has no member named 'power_connection'
./src/video/quartz/SDL_QuartzEvents.m: In function 'QZ_PumpEvents':
./src/video/quartz/SDL_QuartzEvents.m:737: error: 'UsrActivity' undeclared (first use in this function)
./src/video/quartz/SDL_QuartzEvents.m:737: error: (Each undeclared identifier is reported only once
./src/video/quartz/SDL_QuartzEvents.m:737: error: for each function it appears in.)
./src/video/quartz/SDL_QuartzEvents.m:787: error: 'struct SDL_PrivateVideoData' has no member named 'expect_mouse_up'
</pre>
<p>Il suffit d&#8217;aller télécharger <a href="http://trac.macports.org/raw-attachment/ticket/20235/libsdl.patch">le patch qui va bien</a>. Et ensuite de l&#8217;appliquer au fichier qui devrait se trouver ici si vous n&#8217;avez rien modifié : /opt/local/var/macports/sources/rsync.macports.org/release/ports/devel/libsdl/Portfile</p>
<p>Déplacez vous ensuite via le terminal dans le répertoire qui contient le patch téléchargé puis appliquez le, dans mon cas :</p>
<pre class="brush: bash;">
cd Downloads
sudo patch /opt/local/var/macports/sources/rsync.macports.org/release/ports/devel/libsdl/Portfile libsdl.patch
</pre>
<p>Et voilà le tour est joué !</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/logiciel/compiler-libsdl-avec-macports-sous-snow-leopard-93/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Écrire un behavior doctrine (actAs)</title>
		<link>http://blog.devorigin.fr/symfony/ecrire-un-behavior-doctrine-actas-73</link>
		<comments>http://blog.devorigin.fr/symfony/ecrire-un-behavior-doctrine-actas-73#comments</comments>
		<pubDate>Mon, 17 Aug 2009 12:11:27 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[behavior]]></category>
		<category><![CDATA[doctrine]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=73</guid>
		<description><![CDATA[Une des fonctionnalités géniale des ORM est les behaviors. Les behaviors vont permettre de rajouter des fonctionnalités à un objet de manière automatique (le fameux updated_at et created_at que tout le monde connaît). Je vais vous donnerun petit exemple de behavior Doctrine tout simple, à vous de créer les vôtres ensuite.]]></description>
			<content:encoded><![CDATA[<p>Une des fonctionnalités géniale des ORM est les behaviors. Les behaviors vont permettre de rajouter des fonctionnalités à un objet de manière automatique (le fameux updated_at et created_at que tout le monde connaît). Je vais vous donner un petit exemple de behavior Doctrine tout simple, à vous de créer les vôtres ensuite. Merti <a href="http://www.amicalement-web.net/" target="_blank">Tim</a> de m&#8217;avoir forcé à écrire ce post &#8230; <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h1>Le behavior Publishable</h1>
<p>On va imaginer un behavior qui va nous permettre de savoir si un objet est publiable ou pas, en fonction d&#8217;une date de début de publication et une date de fin de publication. On voudrait donc rajouter un champ started_at et ended_at à notre modèle et quelques méthodes qui vont nous permetre d&#8217;y accéder.</p>
<h2>Les templates Doctrine</h2>
<p>C&#8217;est en fait des <a href="http://www.doctrine-project.org/documentation/manual/1_1/en/behaviors#simple-templates" target="_blank">templates Doctrine</a> que vient la magie. C&#8217;est templates vont vous permettre d&#8217;externaliser des parties d&#8217;un modèle et de pouvoir ensuite les affecter à n&#8217;importe quel autre modèle (via le actAs).<br />
Nous allons commencer par créer le qu&#8217;il nous faut dans notre projet Symfony.</p>
<pre class="brush: php;">
mkdir -p lib/Doctrine/Template
</pre>
<p>Dans ce répertoire on va créer un template que l&#8217;on va appeler Publishable.php</p>
<pre class="brush: php;">
&lt;?php
/**
 * Behavior for adding Tagging features to your models
 *
 * @package     Doctrine
 * @subpackage  Template
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @author      Vincent Jousse &lt;vincent.jousse@devorigin.fr&gt;
 */
class Doctrine_Template_Publishable extends Doctrine_Template {

/**
 * Set table definition for Publishable behavior
 *
 * @return void
 */
 public function setTableDefinition() {
 $this-&gt;hasColumn('started_at', 'timestamp');
 $this-&gt;hasColumn('ended_at', 'timestamp');
 }
}
</pre>
<p>La première étape consiste donc à rajouter nos deux champs dans le modèle. Rien de bien transcendant ici. Pour ceux qui ne sont habitués qu&#8217;à la syntaxe Yaml, un petit tour vers la <a href="http://www.doctrine-project.org/documentation/manual/1_1/en/defining-models" target="_blank">doc Doctrine</a> pourra vous être utile. Nous allons maintenant voir comment récupérer les objets.</p>
<h2>Les requêtes</h2>
<p>Nous allons écrire une méthode qui va nous générer une requête qui va nous permettre de récupérer les objets qui sont publiables. Sachant que les objets publiables sont ceux qui ont une date de début de publication nulle ou dans le passé, et une date de fin de publication nulle ou dans le futur.</p>
<pre class="brush: php;">
public function getPublishableQueryTableProxy($time=null,$order=null) {

 if(is_null($time))
 $time = time();

 $q = $this-&gt;getInvoker()
 -&gt;getTable()
 -&gt;createQuery('p')
 -&gt;select('p.*')
 -&gt;where('started_at IS NULL OR started_at &lt;= ?',array($time))
 -&gt;andWhere('ended_at IS NULL OR ended_at &lt; ?',array($time));

 if(!is_null($order))
 $q-&gt;orderBy($order);

 return $q;
 }
</pre>
<p>Vous remarquerez le &#8216;TableProxy&#8217; à la fin du nom de la méthode. Cela va nous permettre d&#8217;appeler la méthode via le getTable() comme ceci :</p>
<pre class="brush: php;">
$this-&gt;content_list = Doctrine::getTable('Content')
-&gt;getPublishableQuery()
-&gt;execute();
</pre>
<h2>Les objets</h2>
<p>Pour parfaire la chose on aimerait bien savoir, une fois qu&#8217;on a notre objet, si il est publiable ou pas. On va donc lui rajouter une méthode isPublishable() pour ce faire. Elle pourrait ressembler à ceci :</p>
<pre class="brush: php;">
/**
 *
 * @param $time a timestamp or null (current time)
 * @return bool true if it's publishable according to the $time else false
 */
 public function isPublishable($time=null) {

 if(is_null($time))
 $time = time();

 $object = $this-&gt;getInvoker();

 $endTime = strtotime($object-&gt;ended_at);
 $startTime = strtotime($object-&gt;started_at);

 return (
 is_null($object-&gt;started_at) &amp;&amp; is_null($object-&gt;ended_at) ||
 $endTime &gt;= $time &amp;&amp; is_null($object-&gt;started_at) ||
 $startTime &lt;= $time &amp;&amp; is_null($object-&gt;ended_at) ||
 $endTime &gt;= $time &amp;&amp; started_at &lt;= $time

 );

 }
</pre>
<p>Je vous épargne les commentaires mais la ligne importante est le</p>
<pre class="brush: php;">
$this-&gt;getInvoker();
</pre>
<p>Qui va vous permettre de récupérer l&#8217;objet auquel vous aurez attaché votre template. Avec cette belle méthode vous pourrez ensuite faire un :</p>
<pre class="brush: php;">
$object-&gt;isPublishable();
</pre>
<p>C&#8217;est magique je vous dis.</p>
<h2>Le schéma</h2>
<p>J&#8217;ai gardé le plus simple pour la fin, une fois votre Template créé, vous n&#8217;avez plus qu&#8217;à modifier votre schéma pour y ajouter le actAs qui va bien, par exemple :</p>
<pre class="brush: plain;">
Content:
tableName: content

actAs:
Timestampable: ~
Publishable: ~
I18n:
fields : [ text ]

columns:
id:
type: integer(4)
primary: true
autoincrement: true
...
</pre>
<p>Et le tour est joué !</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/symfony/ecrire-un-behavior-doctrine-actas-73/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Compter le temps passé sur un projet</title>
		<link>http://blog.devorigin.fr/logiciel/compter-le-temps-passe-sur-un-projet-65</link>
		<comments>http://blog.devorigin.fr/logiciel/compter-le-temps-passe-sur-un-projet-65#comments</comments>
		<pubDate>Tue, 04 Aug 2009 10:12:43 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Logiciel]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[freelance]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=65</guid>
		<description><![CDATA[Beaucoup de développeurs sont bien incapables d'estimer le temps qu'ils vont passer sur un projet, ce qui semble assez compréhensible même si ça vient de plus en plus avec l'expérience. En revanche on devrait être capable de dire combien de temps on a passé sur un projet, et c'est rarement le cas. C'est là qu'intervient TimeEdition.]]></description>
			<content:encoded><![CDATA[<p>Beaucoup de développeurs sont bien incapables d&#8217;estimer le temps qu&#8217;ils vont passer sur un projet, ce qui semble assez compréhensible même si ça vient de plus en plus avec l&#8217;expérience. En revanche on devrait être capable de dire combien de temps on a passé sur un projet, et c&#8217;est rarement le cas. C&#8217;est là qu&#8217;intervient TimeEdition.</p>
<h1>TimeEdition &#8211; Un outil indispensable</h1>
<p>Je ne sais plus comment je suis tombé sur ce petit logiciel, mais je ne peux maintenant plus m&#8217;en passer. Il vous permet de gérer vos différents clients/projets/tâches et de compter le temps que vous passez dessus. Dès que vous commencez à travailler vous appuyez sur le bouton &laquo;&nbsp;Record&nbsp;&raquo; et dès que vous arrêtez vous le stoppez. Si au bout de 3 minutes il voit qu&#8217;il n&#8217;y a plus d&#8217;activité, il proposera de s&#8217;arrêter tout seul.</p>
<div id="attachment_66" class="wp-caption alignnone" style="width: 210px"><img class="size-full wp-image-66" title="timeedition4x" src="http://blog.devorigin.fr/wp-content/uploads/2009/08/timeedition4x.jpg" alt="Captures d'écran de TimeEdition" width="200" height="270" /><p class="wp-caption-text">Captures d&#39;écran de TimeEdition</p></div>
<p>De plus il peut exporter les enregistrements dans la majorité des formats de calendrier, et peut mettre à jour votre iCal ou Google Calendar automatiquement. Il va vous permettre avec le temps de vraiment vous rendre compte le temps que vous passez sur chaque projet, et ça pour un freelance, ça n&#8217;a pas de prix ! (façon de dire <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  )</p>
<p>N&#8217;hésitez pas à aller faire un tour sur le <a title="TimeEdition website" href="http://www.timeedition.com/" target="_blank">site du projet</a>, qui en plus est GPL. Disponible pour Windows et Mac OS X.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/logiciel/compter-le-temps-passe-sur-un-projet-65/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Netbeans &amp; Symfony</title>
		<link>http://blog.devorigin.fr/symfony/netbeans-symfony-43</link>
		<comments>http://blog.devorigin.fr/symfony/netbeans-symfony-43#comments</comments>
		<pubDate>Wed, 08 Jul 2009 08:23:15 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[netbeans]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=43</guid>
		<description><![CDATA[On a entendu parler un peu partout cette semaine du support de Symfony dans l'éditeur Netbeans. J'ai moi même cherché quelques temps un éditeur qui pouvait me convenir pour Symfony. Après TextMate, Eclipse j'ai essayé Netbeans, et je l'ai pour l'instant adopté. Voici un petit résumé des fonctionnalités de Netbeans pour les non anglophones qui eux aussi veulent tester ce nouveau support de Symfony.]]></description>
			<content:encoded><![CDATA[<p>On a entendu parler un peu partout cette semaine du support de Symfony dans l&#8217;éditeur Netbeans. J&#8217;ai moi même cherché quelques temps un éditeur qui pouvait me convenir pour Symfony. Après TextMate, Eclipse j&#8217;ai essayé Netbeans, et je l&#8217;ai pour l&#8217;instant adopté. Voici un petit résumé des fonctionnalités de Netbeans pour les non anglophones qui eux aussi veulent tester ce nouveau support de Symfony.</p>
<h2>Récupération de la version de développement</h2>
<p>Premièrement il faut se rendre sur <a title="Sit de développement de netbeans" href="http://bertram.netbeans.org/hudson/job/PHP-build/lastSuccessfulBuild/" target="_blank">le site de développement de Netbeans</a>. Il va ensuite vous falloir cliquer sur le lien qui est en dessous de la belle traduction francophone &laquo;&nbsp;Artefacts du build&nbsp;&raquo;. À l&#8217;heure où j&#8217;écris ces lignes, c&#8217;est la <a title="Version de développement de netbeans" href="http://bertram.netbeans.org/hudson/job/PHP-build/lastSuccessfulBuild/artifact/nbbuild/NetBeans-dev-2009-07-08_09-04-39%20-php.zip" target="_blank">version 8/07/2009 à 9H04 et 39 secondes <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </a></p>
<p>Une fois le zip extrait allez dans netbeans/bin/netbeans.exe pour les utilisateurs Windows (enfin je présume j&#8217;ai pas pu tester), pour les Mac OS Xiens et autres Unixiens lancez le via un terminal par exemple comme ci-dessous</p>
<pre class="brush: bash;">
cd Desktop/netbeans
./bin/netbeans
</pre>
<h2>Support de Symfony</h2>
<p>Alors qu&#8217;est-ce que cette version apporte ? Tout d&#8217;abord un menu contextuel sur le projet qui va nous permettre de lancer les commandes Symfony.</p>
<div id="attachment_49" class="wp-caption aligncenter" style="width: 236px"><img class="size-medium wp-image-49" title="menu_contextuel" src="http://blog.devorigin.fr/wp-content/uploads/2009/07/menu_contextuel-226x300.png" alt="Menu contextuel symfony netbeans" width="226" height="300" /><p class="wp-caption-text">Menu contextuel symfony netbeans</p></div>
<p>Nous avons ensuite une fenêtre qui nous permet de lancer une des commandes supportée par le script, commandes que l&#8217;on peut filtrer avec des mots-clefs.</p>
<div id="attachment_50" class="wp-caption aligncenter" style="width: 708px"><img class="size-full wp-image-50" title="symfony_commands" src="http://blog.devorigin.fr/wp-content/uploads/2009/07/symfony_commands.png" alt="Commandes symfony de netbeans" width="698" height="542" /><p class="wp-caption-text">Commandes symfony de netbeans</p></div>
<p>Et pour finir petit plus non négligeable, la possibilité d&#8217;affecter un raccourci clavier aux commandes.</p>
<div id="attachment_52" class="wp-caption aligncenter" style="width: 668px"><img class="size-full wp-image-52" title="raccourcis_symfony_netbeans" src="http://blog.devorigin.fr/wp-content/uploads/2009/07/raccourcis_symfony_netbeans.png" alt="raccourcis_symfony_netbeans" width="658" height="429" /><p class="wp-caption-text">Raccourcis clavier netbeans symfony</p></div>
<p>Voilà pour les premières fonctionnalités ajoutées, si vous êtes passé à côté de l&#8217;information et que vous êtes anglophone, vous pouvez aller jeter un œil à l&#8217;<a title="Initial symfony support" href="http://blogs.sun.com/netbeansphp/entry/initial_symfony_support" target="_blank">article original de </a><span style="font-style: italic;"><a title="Initial symfony support" href="http://blogs.sun.com/netbeansphp/entry/initial_symfony_support" target="_blank">Tomas Mysik</a>.</span></p>
<h2>Complétion du code</h2>
<p>Juste une dernière petite astuce à laquelle je n&#8217;avais pas fait attention au début et qui se trouve fort utile. Lorsque vous créez une action, un component, un form ou je ne sais quoi d&#8217;autre, n&#8217;oubliez pas de définir l&#8217;attribut @package ou @subpackage dans vos commentaires en entête pour que Netbeans vous propose la complétion des méthodes.</p>
<div id="attachment_54" class="wp-caption aligncenter" style="width: 417px"><img class="size-full wp-image-54" title="package_netbeans" src="http://blog.devorigin.fr/wp-content/uploads/2009/07/package_netbeans.png" alt="Commentaire @package @subpackage netbeans" width="407" height="161" /><p class="wp-caption-text">Commentaire @package @subpackage netbeans</p></div>
<h2>Conclusion</h2>
<p>Si vous cherchez un éditeur de code performant pour faire du Symfony et surtout pas trop lourd n&#8217;hésitez pas à essayer Netbeans. Car en effet, même si je n&#8217;en ai pas parlé jusqu&#8217;ici, netbeans a la particularité d&#8217;être beaucoup moins lourd qu&#8217;Eclipse. Et si des fois il commence à prendre un peu trop de RAM, vous pouvez lancer vous même le Garbage Collector pour qu&#8217;il fasse du ménage en cliquant sur la petite icône de la mémoire (on l&#8217;active avec un click droit sur cette même barre d&#8217;icônes).</p>
<div id="attachment_55" class="wp-caption aligncenter" style="width: 362px"><img class="size-full wp-image-55" title="netbeans_memory_usage" src="http://blog.devorigin.fr/wp-content/uploads/2009/07/netbeans_memory_usage.png" alt="Occupation mémoire de netbeans" width="352" height="64" /><p class="wp-caption-text">Occupation mémoire de netbeans</p></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/symfony/netbeans-symfony-43/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Optimiser les Nested Set Doctrine quand i18n est activé</title>
		<link>http://blog.devorigin.fr/symfony/optimiser-les-nested-set-doctrine-quand-i18n-est-active-5</link>
		<comments>http://blog.devorigin.fr/symfony/optimiser-les-nested-set-doctrine-quand-i18n-est-active-5#comments</comments>
		<pubDate>Mon, 06 Jul 2009 14:26:39 +0000</pubDate>
		<dc:creator>vjousse</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[nested set]]></category>

		<guid isPermaLink="false">http://blog.devorigin.fr/?p=5</guid>
		<description><![CDATA[Je ne dois pas être le seul à utiliser les Nested Set de Doctrine dans mes projets Symfony pour réaliser les menus d'un site. Mais jusqu'ici, je n'avais pas vraiment prêté attention aux requêtes effectuées pour afficher un menu racine et ses descendants quand l'internationalisation (i18n) est activée. Depuis, je suis passé de 10 requêtes à ... 3. Petit tour d'horizon.]]></description>
			<content:encoded><![CDATA[<p>Je ne dois pas être le seul à utiliser les Nested Set de Doctrine dans mes projets Symfony pour réaliser les menus d&#8217;un site. Mais jusqu&#8217;ici, je n&#8217;avais pas vraiment prêté attention aux requêtes effectuées pour afficher un menu racine et ses descendants quand l&#8217;internationalisation (i18n) est activée. Depuis, je suis passé de 10 requêtes à &#8230; 3. Petit tour d&#8217;horizon.</p>
<h2>Mes fichiers avant modification</h2>
<p>Premièrement mon action ressemblait tout simplement à ce qui va suivre, à savoir la récupération de tous les menus racines, rien de bien original. Il faut quand même garder à l&#8217;esprit que ce que je vous présente ici, n&#8217;a réellement d&#8217;intérêt que si votre table est multilingue ou a une relation avec une autre table.</p>
<pre class="brush: php;">
public function executeList(sfWebRequest $request)
{
$this-&gt;roots = Doctrine::getTable('Menu')-&gt;getTree()-&gt;fetchRoots();
}
</pre>
<p>Ensuite dans mon premier partial (_list), j&#8217;avais uncode qui récupère les enfants du nœud racine :</p>
<pre class="brush: php;">

foreach ($roots as $root) {
echo $root-&gt;name . '&lt;br /&gt;';
echo '&lt;ul id=&quot;order'. $root-&gt;id . '&quot;&gt;';
include_partial('doMenu/children',array(
'children' =&gt; $root-&gt;getNode()-&gt;getChildren()
));
echo '&lt;/ul&gt;';
}
</pre>
<p>Et dans mon partial _children un simple affichage de chaque enfant :</p>
<pre class="brush: php;">
&lt;?php
foreach ($children as $child) {
echo '&lt;li id=&quot;menu_' . $child-&gt;id . '&quot; class=&quot;sortable&quot;&gt;&lt;a href=&quot;' . url_for('doMenu/edit?id=' . $child-&gt;id ). '&quot;/&gt;' . $child . '&lt;/a&gt;&lt;/li&gt;';
}
</pre>
<p>Sauf que ça a beau être basique, il nous faut une requête pour l&#8217;action qui récupère l&#8217;arbre, ensuite 1 requête pour récupérer la traduction du Menu dans le partial _list (actAs: i18N pour mon modèle Menu), 2 autres dans _list pour avoir les descendants du menu racine, et pour chaque descendant, une autre requête pour récupérer la traduction &#8230; ouf !<br />
Soit pour moi un beau total de 10 requêtes (les plus aguerris d&#8217;entre vous aurons noté que dans mon cas j&#8217;ai 6 descendants <img src='http://blog.devorigin.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  )</p>
<p>Alors évidemment on va nettoyer un peu tout ça et on va éliminer les requêtes de traduction qui ralentissent le tout &#8230;</p>
<h2>Création de la requête à la main</h2>
<p>Au lieu de passer par la méthode Doctrine::getTable, nous allons écrire notre requêtes à la main, ce qui va nous permettre d&#8217;inclure directement les traductions. Nous allons procéder comme expliqué dans la <a title="Documentation doctrine" href="http://www.doctrine-project.org/documentation/manual/1_1/en/hierarchical-data#nested-set:advanced-usage:fetching-a-tree-with-relations" target="_blank">doc Doctrine</a> pour récupérer un arbre et ses relations.</p>
<pre class="brush: php;">
public function executeList(sfWebRequest $request)
{

$q = Doctrine_Query::create()
-&gt;select('m.id, t.name')
-&gt;from('Menu m')
-&gt;leftJoin('m.Translation t');

$treeObject = Doctrine::getTable('Menu')-&gt;getTree();
$treeObject-&gt;setBaseQuery($q);
$this-&gt;roots = $treeObject-&gt;fetchRoots();
$treeObject-&gt;resetBaseQuery();
}
</pre>
<p>Nous passons ici de 10 à 9 requêtes. Tout ça pour ça ? Eh oui, la seule requête de traduction qui a été enlevée est la première qui était effectuée dans _list pour le menu racine, les autres (pour les enfants) sont toujours là. Pourquoi ? Tout simplement à cause du resetBaseQuery qui réinitialise la requête et nous enlève notre join sur la table translation. Même si il est conseillé de le faire dans la doc Doctrine, ce n&#8217;est pas le cas pour nous ici, nous voulons garder la même requête de l&#8217;arbre pour les enfants. Ce qui nous donne ceci :</p>
<pre class="brush: php;">
public function executeList(sfWebRequest $request)
{

$q = Doctrine_Query::create()
-&gt;select('m.id, t.name')
-&gt;from('Menu m')
-&gt;leftJoin('m.Translation t');

$treeObject = Doctrine::getTable('Menu')-&gt;getTree();
$treeObject-&gt;setBaseQuery($q);
$this-&gt;roots = $treeObject-&gt;fetchRoots();
}
</pre>
<p>Nous nous retrouvons maintenant avec uniquement 3 requêtes, et surtout avec un nombre de requêtes qui n&#8217;augmentera plus avec le nombre de descendants du nœud racine.</p>
<h2>Conclusion</h2>
<p>Même si on a tendance à l&#8217;oublier, il faut toujours garder un œil sur le nombre de requêtes que Doctrine peut générer. Comme il est répété dans la documentation de Doctrine, il vaut mieux toujours créer sa requête &laquo;&nbsp;à la main&nbsp;&raquo; en ne récupérant que les informations dont on a besoin, et surtout toutes les informations dont on a besoin, au risque que Doctrine aille les chercher via des requêtes supplémentaires.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.devorigin.fr/symfony/optimiser-les-nested-set-doctrine-quand-i18n-est-active-5/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
