Flux RSS de gandbox.fr - ez publish Flux RSS de gandbox.fr - ez publish Thu, 10 Mar 2011 13:10:21 +0000 http://www.gandbox.fr/rss2 Retour aux affaires : eZ Publish, la création d'un board, RFC du cycle de release <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/ez-publish-cles-de-maison/20943-1-fre-FR/ez-publish-cles-de-maison.jpg" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/ez-publish-cles-de-maison/20943-1-fre-FR/ez-publish-cles-de-maison_medium.jpg" width="200" height="150" style="border: 0px;" alt="ez publish - clés de maison" title="ez publish - clés de maison" /> </a> </p></div><p>Après <b>un passage 2010 / 2011 très positivement chargée</b> (bébé, déménagement), ou très négativement perturbée (1 mois d'écrasement de ligne aDSL... Merci FT), il est temps de &quot;<b>retourner aux affaires</b>&quot;. Après quelques années d'expertise sur le déploiement d'<b><a href="http://share.ez.no/" target="_blank">eZ Publish</a></b>, c'est avec une grande fierté, pas mal d'excitation, et un peu de stress... <b>que <a href="http://share.ez.no/blogs/community-project-board/hello-world-we-are-the-ez-publish-community-project-board" target="_blank">j'ai rejoint le board du projet communautaire eZ Publish</a></b>.</p><p>Connaissant la légendaire aisance des français à manipuler l'anglais (<a href="http://vupar.wordpress.com/2010/05/07/pourquoi-les-francais-parlent-mal-langlais-selon-une-francaise/" target="_blank">voir ce témoignage</a>), et en bon représentant des cancres shakespeariens (@nico @gaetano : qui me vaut quelques moments de solitudes sur skype), voici une petite synthèse de l'historique du projet communautaire, en préambule du sujet important : <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Retour-aux-affaires-eZ-Publish-la-creation-d-un-board-RFC-du-cycle-de-release#rfc" target="_self"><b>l'appel à commentaires pour le cycle de release d'eZ Publish</b></a>.</p><a name="eztoc20935_1" id="eztoc20935_1"></a><h2>Juin 2010 à Berlin : l'annonce de la création d'une version communautaire, et d'une version entreprise</h2><p>A berlin, en Juin 2010, eZ Systems annonce l'<b>ouverture du code du Kernel eZ Publish à la contribution communautaire</b>, et de ce fait la constitution de 2 versions d'eZ Publish : la <b>version communautaire</b> (la version dîtes &quot;innovante&quot;, qui contient le code communautaire le plus récent &amp; donc parfois expérimental) et la <b>version entreprise</b> (la version supportée par l'éditeur, suite à une phase d'assurance qualité). Voir l'annonce officielle, avec le nouveau lien qui marche : <a href="http://ez.no/Events-news/News/eZ-Systems-set-to-boost-innovation-while-enhancing-business-value-to-professional-users" target="_blank">http://ez.no/Events-news/News/eZ-Systems-set-to-boost-innovation-while-enhancing-business-value-to-professional-users</a>.</p><p>Cette annonce a provoquée pas mal de débats et d'inquiétudes dans la communauté, avec les classiques questions (voir ce <a href="http://share.ez.no/forums/discussions/no-non-enterprise-version-of-ez-publish-in-the-future" target="_blank">topic</a> ou encore ce <a href="http://share.ez.no/forums/discussions/feedback-regarding-the-ez-community-entreprise-announcement" target="_blank">topic</a>) : <b>les 2 versions vont elles diverger ?</b> <b>Si oui, alors comment migrer d'une version vers l'autre ?</b> Quel sera le cycle de release de la version communautaire ? etc... autant de questions légitimes, et plutôt inévitables, puisque le plan de communication était quelques peu sarkozien : on annonce l'objectif, on verra ensuite comment la mise en oeuvre se fait :)</p><a name="eztoc20935_2" id="eztoc20935_2"></a><h2>Septembre 2010 sur share.ez.no : Annonce de la création future d'un Project Board</h2><p>Nicolas Pastorino, notre cher community manager, présente les grandes lignes des rôles et des responsabilités du Board, ainsi que la méthode de sélection des membres. Voir ici l'article complet : <a href="http://share.ez.no/blogs/ez/the-community-project-step-1-governance" target="_blank">The Community Project step 1 : Governance</a></p><p>Ce premier jet sert de trame au document de travail sur le rôle de la gouvernance : <a href="http://share.ez.no/community-project/governance-framework-document" target="_blank">Governance - Framework document</a>.</p><p><b>Voici une synthèse de ce qu'il faut retenir, en une seule phrase :</b></p><blockquote><span class="quoteleft">“</span><p>Le projet board est constitué de 6 membres élu pour 1 an (3 d'eZ Systems et 3 de la communauté), qui décident par un système de vote des grandes orientations du projet communautaire d'eZ Publish (règles de contributions, road-map, cycles de release), et qui assurent un relais d'information interne (membres de la communauté) &amp; externe (évènements, promotion).</p><span class="quoteright">”</span></blockquote> <a name="eztoc20935_3" id="eztoc20935_3"></a><h2>Migration vers Github</h2><p>Le projet eZ Publish (Kernel) à migré progressivement de SVN vers <b>GitHub</b> (<a href="https://github.com/ezsystems/ezpublish" target="_blank">https://github.com/ezsystems/ezpublish</a>), qui est un outil spécifiquement dédié au développement communautaire (branches, fusions de codes, dépôts décentralisés, pull requests, interfaces intuitives, statistiques, historiques, etc.). Les extensions sont par contre toujours sur <a href="http://projects.ez.no/" target="_self">http://projects.ez.no/</a> (SVN la plupart du temps).</p><a name="eztoc20935_4" id="eztoc20935_4"></a><h2>Février 2011 sur share.ez.no : Annonce de la constitution du Board</h2><p>Présentation rapide de l'équipe, que j'apprends à connaître (pour certains).</p> <ul> <li><b><a href="http://share.ez.no/community/profile/9804" target="_blank">Nicolas Pastorino (FR)</a> </b>: le &quot;chairman&quot;, le charismatique et tout puissant président dont les voix comptes double (c'est plus pratique pour un vote de 6 membres...), <a href="http://www.linkedin.com/in/nicolaspastorino" target="_self">voir sur linkedin</a></li> <li><b><a href="http://share.ez.no/community/profile/10838" target="_blank">Robin Muilwijk (NL)</a> :</b> ex-community manager du projet Joomla! (formidable retour d'expérience), <a href="http://www.linkedin.com/in/robinmuilwijk" target="_blank">voir sur linkedin</a></li> <li><b><a href="http://share.ez.no/community/profile/10567" target="_blank">Andrew Duck (VN / NZ)</a> :</b> Représentant du continant asiatique (intégrateur eZ Publish expérimenté : <a href="http://quiqcorp.com/" target="_self">http://quiqcorp.com/</a>), <a href="http://www.linkedin.com/in/andrewduck" target="_self">voir sur linkedin</a></li> <li><b><a href="http://share.ez.no/community/profile/11248" target="_blank">Gaetano Giunta (FR / IT)</a> :</b> Ingénieur eZ Systems, consultant &amp; polémiste célèbre (eric zemmour ? ... dans ce cas je serais eric naulleau ?), <a href="http://www.linkedin.com/in/gggeek" target="_blank">voir sur linkedin</a></li> <li><b><a href="http://share.ez.no/community/profile/9710" target="_blank">Ole Marius Smestad (NO)</a> :</b> Ingénieur eZ Systems, gros contributeur eZ Publish, le norvégien de l'équipe</li> <li><b><a href="http://share.ez.no/community/profile/90262" target="_blank">Moi (Gilles Guirand)</a> :</b> Consultant eZ chez un partenaire platinum, donc avec un pied dans les 2 univers eZ Publish, <a href="http://www.linkedin.com/in/gillesguirand" target="_self">voir sur linkedin</a></li> </ul> <p>L'article complet : <a href="http://share.ez.no/blogs/community-project-board/hello-world-we-are-the-ez-publish-community-project-board" target="_blank">http://share.ez.no/blogs/community-project-board/hello-world-we-are-the-ez-publish-community-project-board</a></p><a name="eztoc20935_5" id="eztoc20935_5"></a><h2> <a name='rfc'></a>Appels à commentaires sur le cycle de release d'eZ Publish (RFC - Request for comments)</h2><p>La premier publication du Board concerne le stratégique sujet du cycle de release d'eZ Publish et de la synchronisation avec la version enterprise. Pour ceux qui ont la flemme de lire quelques slides en anglais, voici une synthèse de la proposition : </p> <ul> <li><b>1 seul dépôt Git</b> pour les ingénieurs eZ Systems &amp; la communauté, donc pas de fork entre la version communautaire &amp; enterprise (cela répond déjà à quelques inquiétudes)</li> <li><b>1 cycle de release de 6 mois </b>(4 mois de développement, 2 mois d'assurance qualité), avec d'éventuelles releases intermédiaires tous les 2 mois <ul> <li><b>4 mois de développement</b> sur la branche &quot;master&quot;</li> <li><b>2 mois d'assurance qualité</b> sur la branche &quot;master&quot; (uniquement du correctif, plus de nouvelle fonctionnalités)</li> </ul> </li> <li>Si d'éventuelles fonctionnalité sont produites pendant cette période, elle sont stockés sur une branche &quot;innovation&quot;, puis fusionnées sur le &quot;master&quot; après la période de 2 mois d'assurance qualité</li> </ul> <p> <b>Merci pour les retours &amp; commentaires, de préférence sur l'article lui-même : </b><br /> <a href="http://share.ez.no/blogs/community-project-board/rfc-ez-publish-community-project-release-policy" target="_self">http://share.ez.no/blogs/community-project-board/rfc-ez-publish-community-project-release-policy</a> <br /> <br />Sinon sur cet article en français, je ferais le relais.</p><div class="video"> <object width="580" height="450" type="application/x-shockwave-flash" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=ezpublishcommunityprojectboard-rfc-releasepolicy-110224022039-phpapp01&amp;stripped_title=rfc-release-policy-ez-publish-community-project-board&amp;userName=jeanvoye "> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=ezpublishcommunityprojectboard-rfc-releasepolicy-110224022039-phpapp01&amp;stripped_title=rfc-release-policy-ez-publish-community-project-board&amp;userName=jeanvoye "></param> <param name="allowfullscreen" value="true"></param> </object> </div> Thu, 10 Mar 2011 13:10:21 +0000 http://gandbox.fr/Blogs/Technologies-Web/Retour-aux-affaires-eZ-Publish-la-creation-d-un-board-RFC-du-cycle-de-release Slides eZ Publish du RMLL 2010 <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/rmll-2010-logo/20655-1-fre-FR/RMLL-2010-Logo.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/rmll-2010-logo/20655-1-fre-FR/RMLL-2010-Logo_medium.png" width="181" height="138" style="border: 0px;" alt="RMLL 2010 Logo" title="RMLL 2010 Logo" /> </a> </p></div><p>Cet été, j'ai présenté 2 conférences aux <a href="http://2010.rmll.info/" target="_blank">RMLL 2010</a> (<b>Rencontres Mondiales du Logiciel Libre</b>), ou disons plutôt une conférence divisée en 2 chapitres : <a href="http://2010.rmll.info/Integration-d-eZ-Publish-a-un-systeme-d-information.html" target="_blank">Intégration d’eZ Publish à un système d’information</a> et <a href="http://2010.rmll.info/Travailler-avec-eZ-Find-et-SolR.html" target="_blank">Travailler avec eZ Find et SolR</a>. L'audience était essentiellement constituée de profanes en <a href="http://ez.no/" target="_blank">eZ Publish</a>, les slides assez techniques n'illustrent pas forcement le discours simplifié pour l'occasion.</p><p>Cependant, ces slides (abondement recyclés d'autres conférences) constituent un support de présentation graphique permettant d'illustrer divers sujets qui gravitent autour d'<a href="http://ez.no/" target="_blank">eZ Publish</a>, comme par exemple les références connues, le buiseness model, les concepts de bases, la brique de recherche <a href="http://ez.no/eZPublish/Core-features/eZ-Find-Enterprise-Search" target="_blank">eZ Find</a> et son couplage avec <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a>, etc... En espérant que cela puisse aider quelques personnes dans la communauté à populariser eZ Publish.</p><p><b>Voici le sommaire des slides en anglais :</b></p> <ul> <li>Introduction about eZ Publish</li> <li>Custom &amp; complex data modeling</li> <li>Website factory &amp; cross-content publishing</li> <li>API &amp; External data integration (XML, SOAP, LDAP)</li> <li>Conclusion &amp; questions</li> </ul> <p><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Slides-eZ-Publish-du-RMLL-2010#slides" target="_self">Voir les slides de la conférence sur slideshare</a></p><a name="eztoc20647_1" id="eztoc20647_1"></a><h2> <a name='slides'></a>Slides eZ Publish du RMLL 2010</h2><div class="video"> <object width="600" height="450" type="application/x-shockwave-flash" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20100707ezrmllgigv1-101011131524-phpapp01&amp;stripped_title=20100707-e-zrmllgigv1&amp;userName=gandbox"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20100707ezrmllgigv1-101011131524-phpapp01&amp;stripped_title=20100707-e-zrmllgigv1&amp;userName=gandbox"></param> <param name="allowfullscreen" value="true"></param> </object> </div> Tue, 12 Oct 2010 22:38:17 +0000 http://gandbox.fr/Blogs/Technologies-Web/Slides-eZ-Publish-du-RMLL-2010 eZ Conference 2010 slides about eZ Find 2.2 customization & advanced development <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-conference-ez-find-cover-slides/20211-1-fre-FR/eZ-Conference-eZ-Find-cover-slides.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-conference-ez-find-cover-slides/20211-1-fre-FR/eZ-Conference-eZ-Find-cover-slides_medium.png" width="200" height="149" style="border: 0px;" alt="eZ Conference - eZ Find cover slides" title="eZ Conference - eZ Find cover slides" /> </a> </p></div><p>On <b>June 24th</b>, at the <a href="http://ez.no/fr/company/ez_conference_awards/developer_track" target="_blank">2010 eZ Conference developer track</a>, I proposed a talk about <b>eZ Find 2.2 customization &amp; advanced development</b>. This talk illustrate and summarize <a href="http://www.gandbox.fr/Blogs/Technologies-Web/eZ-Conference-2010-slides-about-eZ-Find-2.2-customization-advanced-development#articles" target="_self">my eZ Find articles / tutorials you'll find below</a>, with new schemas and real project exemples. Thanks to all the eZ Community for their interest and questions during the conference. I hope to have time to write one of <a href="http://share.ez.no/tutorials/write-a-tutorial-win-an-award" target="_blank">these requested tutorials in coming month</a>.</p><p>I'd like to thanks <b>Nicolas Pastorino</b> for the english translation of my articles on <a href="http://share.ez.no/" target="_blank">share.ez.no</a>.</p><p><a href="/content/download/3583/20215/version/1/file/20100622_eZ_Find_Slides_GiG_V2.1.pdf" target="_self" class="download">Download the PDF version</a>, or <a href="http://www.gandbox.fr/Blogs/Technologies-Web/eZ-Conference-2010-slides-about-eZ-Find-2.2-customization-advanced-development#slideshare" target="_self">browse the slideshare version</a>.</p><a name="eztoc20203_1" id="eztoc20203_1"></a><h2> <a name='slideshare'></a>Slideshare version</h2><div class="video"> <object width="600" height="450" type="application/x-shockwave-flash" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20100622ezfindslidesgigv2-1-100627082934-phpapp02&amp;stripped_title=20100622-e-zfindslidesgigv21"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20100622ezfindslidesgigv2-1-100627082934-phpapp02&amp;stripped_title=20100622-e-zfindslidesgigv21"></param> <param name="allowfullscreen" value="true"></param> </object> </div> <a name="eztoc20203_2" id="eztoc20203_2"></a><h2> <a name='articles'></a>Articles / tutorials about eZ Find</h2><p><b>French articles about eZ Find on <a href="http://www.gandbox.fr" target="_self">gandbox.fr</a> :</b></p> <ul> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-1-La-gestion-des-datatypes-entre-eZ-Find-Solr" target="_self">Développement avancé avec eZ Find (partie 1 : La gestion des datatypes entre eZ Find &amp; Solr)</a></li> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-2-Indexer-des-champs-supplementaires-dans-Solr" target="_self">Développement avancé avec eZ Find (partie 2 : Indexer des champs supplémentaires dans Solr)</a></li> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-3-Tirer-profit-de-la-syntaxe-Solr" target="_self">Développement avancé avec eZ Find (partie 3 : Tirer profit de la syntaxe Solr)</a></li> </ul> <p><b>English articles about eZ Find (translation from French), on <a href="http://share.ez.no" target="_blank">share.ez.no</a> :</b></p> <ul> <li><a href="http://share.ez.no/tutorials/ez-publish/advanced-development-with-ez-find-part-1-datatypes-in-solr-and-ez-find" target="_blank">Advanced development with eZ Find - part 1 : Datatypes in Solr and eZ Find</a></li> <li><a href="http://share.ez.no/tutorials/ez-publish/advanced-development-with-ez-find-part-2-indexing-additional-fields-in-solr" target="_blank">Advanced development with eZ Find - part 2 : Indexing additional fields in Solr</a></li> <li>Advanced development with eZ Find - part 3 : Not yet publish... coming soon</li> </ul> Sun, 27 Jun 2010 15:34:50 +0000 http://gandbox.fr/Blogs/Technologies-Web/eZ-Conference-2010-slides-about-eZ-Find-2.2-customization-advanced-development Développement avancé avec eZ Find (partie 3 : Tirer profit de la syntaxe Solr) <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-3/20011-1-fre-FR/eZ-Find-Chapter-3.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-3/20011-1-fre-FR/eZ-Find-Chapter-3.png" width="185" height="102" style="border: 0px;" alt="eZ Find - Chapter 3" title="eZ Find - Chapter 3" /> </a> </p></div><p>Le <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-2-Indexer-des-champs-supplementaires-dans-Solr" target="_self">billet précédent décrit comment ajouter des champs supplémentaires dans Solr</a>, afin de pouvoir les exploiter avec la syntaxe native d'<a href="http://ez.no/ezfind" target="_blank">eZ Find</a> sous la forme<b> 'mycontentclass/mycontentattribute/mycontentsubattribute'</b>.</p><p>Cette syntaxe spécifique à <a href="http://ez.no/ezfind" target="_blank">eZ Find</a> est certes confortable mais non exclusive, à savoir qu'il est possible de <b>mixer des éléments de syntaxes eZ Find et des éléments de syntaxes Solr</b>, comme par exemple les noms des champs (<b>'attr_myfield_type'</b>) ou encore des opérateurs logiques (<b>AND</b>, <b>NOT</b>, etc.).</p><blockquote><span class="quoteleft">“</span><p> - <b>OUI c'est une mauvaise pratique</b>. Une syntaxe 'interface' n'est pas faites pour être outrepasser, au risque de compromettre l'évolutivité de la couche basse, à savoir <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a><br />- <b>OUI cela peut faciliter les développements</b>, voir même sauver la vie du développeur sur certaines situations complexes</p><span class="quoteright">”</span></blockquote> <p>Ce billet montre quelques exemples d'exploitation de la syntaxe <b>Solr</b>, volontairement simplifiés pour en faciliter la compréhension.</p><a name="eztoc20003_1" id="eztoc20003_1"></a><h2>Faire un tri sur un attribut commun à plusieurs classes</h2><p>Il s'agit d'un grand classique des problématiques d'<b>eZ Publish</b>, à savoir : </p> <ul> <li>On crée 2 classes différentes pour X raisons &quot;<b>Post</b>&quot; et &quot;<b>Article</b>&quot;</li> <li>On ajoute dans chacune des classes des attributs communs, parceque utile dans les 2 cas, par exemple un attribut &quot;<b>Date</b>&quot;</li> </ul> <p><b>Résultat : </b>Impossible de mélanger les &quot;<b>Post</b>&quot; et &quot;<b>Article</b>&quot; en les triant par dates décroissante (sauf à développer un terrifiant <a href="http://ezpedia.org/ez/template_operators" target="_blank">opérateur de template</a>). Généralement, les développeurs font en sorte d'utiliser une seule classe plus générique afin de contourner ou plutôt déplacer le problème (la mutualisation d'une classe peut avoir d'autres inconvénients).</p><p><b>La solution des attributs communs entre les classes avec eZ Find :</b></p><p><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-1-La-gestion-des-datatypes-entre-eZ-Find-Solr" target="_self">Le premier billet de cette série consacré à <b>eZ Find</b> décrit la logique de nommage des champs dans <b>Solr</b></a>. Une effet secondaire positif de cette convention (lié au concept de dynamicfields de <b>Solr</b>) est <b>l'absence bienheureuse de l'identifiant de la classe dans le nom de chaque champs</b>. Il est ainsi possible d'exploiter les <b>champs homonymes</b> comme bon nous semble, au travers de recherche, filtres ou tris en fonction du besoin.</p><p><b>Exemple de code de template eZ Publish sur la seule classe &quot;Post&quot; :</b></p> <pre class="eztemplate"><span style="color: #D36900;">&#123;</span>def <span style="">$search_result</span> = <a href="http://ez.no/doc/content/advancedsearch?SearchText=fetch"><span style="color: #008000;">fetch</span></a><span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'content'</span>, <span style="color: #ff0000;">'list'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'parent_node_id'</span>, <span style="color: #cc66cc;">2</span>, <span style="color: #ff0000;">'class_filter_type'</span>, <span style="color: #ff0000;">'include'</span>, <span style="color: #ff0000;">'class_filter_array'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #cc66cc;">24</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'sort_by'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span> <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'attribute'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=false"><span style="color: #0600FF;">false</span></a><span style="color: #D36900;">&#40;</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'post/date'</span> <span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'limit'</span>, <span style="color: #cc66cc;">10</span>, <span style="color: #ff0000;">'depth'</span>, <span style="color: #cc66cc;">3</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> &nbsp;</pre><p><b>Exemple équivalent de code de template eZ Find pour notre problématique de tri inter-classes &quot;Post&quot; et &quot;Article&quot; :</b></p> <pre class="eztemplate"><span style="color: #D36900;">&#123;</span>def <span style="">$search</span>=<a href="http://ez.no/doc/content/advancedsearch?SearchText=fetch"><span style="color: #008000;">fetch</span></a><span style="color: #D36900;">&#40;</span> ezfind, search, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span> query , <span style="color: #ff0000;">''</span>, <span style="color: #ff0000;">'class_id'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'post'</span>, <span style="color: #ff0000;">'article'</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'limit'</span>, <span style="color: #cc66cc;">10</span>, <span style="color: #ff0000;">'sort_by'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'attr_date_dt'</span>, <span style="color: #ff0000;">'desc'</span><span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> &nbsp;</pre><p><b>A noter :</b> une évolution souhaitable d'<b>eZ Find</b> serait de pouvoir exploiter une syntaxe du type '<b>//date</b>', afin de rendre facultatif l'ajout de la classe dans le filtre <b>Solr</b> généré.</p><a name="eztoc20003_2" id="eztoc20003_2"></a><h2>Travailler avec les keywords</h2><p>Contrairement à l'exemple précédent sur les dates, les <b>keywords</b> disposent dans <b>eZ Publish</b> d'une table externe au contenu (<b>ezkeyword_attribute_link</b>), permettant de lier chaque <b>keyword</b> à divers contenus de diverses classes. Cependant <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/modules/content/fetch_functions/keyword" target="_blank">le fetch par keyword</a> ne dispose pas de tous les filtres possibles d'un <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/modules/content/fetch_functions/list" target="_blank">fetch par list</a> par exemple (<b>class_filter_type, class_filter_array, extended_attribute_filter</b>, etc.). Cette limitation se comprend puisque permettre un filtre inter-classes engendre forcement une limitation sur les fonctionnalités liées aux attributs spécifiques à chaque classes.</p><p>Sur le même logique que le traitement par date, on peut donc exploiter <b>eZ Find</b> pour effectuer toutes les opérations nécessaires autour des <b>keywords</b>. Voici un exemple de code :</p> <pre class="eztemplate">'filter', array('attr_tags_lk:&quot;ez publish&quot;', 'NOT attr_title_t:&quot;RSS&quot;') &nbsp;</pre><p><b>Résultat :</b> Retourne uniquement les résultats associés au keyword &quot;<b>eZ Publish</b>&quot; ou &quot;<b>ez publish</b>&quot; (notez l'utilisation du <b>_lk</b> pour lowercase), ne contenant pas &quot;<b>RSS</b>&quot; dans le titre</p> <pre class="eztemplate">'filter', array('attr_tags_lk:&quot;ez publish&quot;', 'attr_tags_lk:&quot;mootools&quot;') &nbsp;</pre><p><b>Résultat :</b> Retourne uniquement les résultats associés à la fois au keyword &quot;<b>eZ Publish</b>&quot; ou &quot;<b>ez publish</b>&quot;, et au keyword &quot;<b>Mootools</b>&quot; ou &quot;<b>mootools</b>&quot;</p><a name="eztoc20003_3" id="eztoc20003_3"></a><h2>Faire des filtres complexes</h2><p>Voici quelques exemples de filtres, qui n'ont rien d'exhaustif puisqu'il est possible d'exploiter <a href="http://lucene.apache.org/java/2_9_1/queryparsersyntax.html" target="_blank">l'ensemble des opérateurs Lucene</a> en fonction de la version de Solr déployée (version de <b>Solr 1.4</b>, disponible dans <b>eZ Find 2.2</b> lors de la rédaction de ce billet).</p> <pre class="eztemplate">'filter', array('NOT ( attr_title_t:(ez+find) OR attr_intro_t:(ez+find) )') &nbsp;</pre><p><b>Résultat : </b>Retourne uniquement les résultats qui possèdent l'expression '<b>ez find</b>' ou '<b>eZ Find</b>', dans l'attribut '<b>title</b>' ou l'attribut '<b>Intro</b>'. Il faut noter l'utilisation de la version '<b>text</b>' (<b>_t</b>) sur l'attribut '<b>title</b>' permettant de profiter du non respect de la casse (contrairement au type '<b>string</b>').</p> <pre class="eztemplate">'filter', array('attr_title_s:[A TO G] AND ezf_df_text:google~0.7') &nbsp;</pre><p><b>Résultat : </b>Retourne uniquement les résultats dont le '<b>title</b>' commence par A,B,C,D, E ou F (G exclu), et dont le contenu possède approximativement l'expression '<b>google</b>' (Google, iGoogle, etc.).</p> <ul> <li><b>A noter : </b>Le ratio '0.7' peut être ajuster au besoin</li> <li><b>A noter : </b>le champs <b>'ezf_df_text'</b> est un champs constitué dynamiquement et par recopie de tous les autres champs de types <b>'string'</b>, <b>'text'</b> ou <b>'keyword'</b>. On peut aussi utiliser le champs <b>'ezf_sp_words'</b> si la fonctionnalité de spellcheck est exploitable. Voir le fichier <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fjava%2Fsolr%2Fconf%2Fschema.xml" target="_blank">schema.xml</a> et la définition de ces champs par <a href="http://wiki.apache.org/solr/SchemaXml#Copy_Fields" target="_blank">copyField</a> pour plus de détail.</li> </ul> Sun, 23 May 2010 17:17:36 +0000 http://gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-3-Tirer-profit-de-la-syntaxe-Solr Développement avancé avec eZ Find (partie 2 : Indexer des champs supplémentaires dans Solr) <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-2/19880-1-fre-FR/eZ-Find-Chapter-2.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-2/19880-1-fre-FR/eZ-Find-Chapter-2.png" width="185" height="102" style="border: 0px;" alt="eZ Find - Chapter 2" title="eZ Find - Chapter 2" /> </a> </p></div><p>Le <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-1-La-gestion-des-datatypes-entre-eZ-Find-Solr" target="_self">billet précédent</a> décrit les mécanismes bas niveaux d'<a href="http://ez.no/ezfind" target="_blank">eZ Find</a>, et la façon dont les <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-1-La-gestion-des-datatypes-entre-eZ-Find-Solr" target="_self">correspondances entre les attributs <b>eZ Publish</b> (noms, types de champs) et les champs Solr</a> sont gérés. <b>Ce billet décrit comment eZ Find peut considérablement faciliter le développement de certaines fonctionnalités</b> (en évitant de complexes opérateurs de templates aux multiples requêtes SQL...), en ajoutant automatiquement des champs dans <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> lors de l'indexation d'un contenu, ré-exploitables par la suite pour la construction d'une facette par exemple ou pour profiter d'un filtre supplémentaire.</p><a name="eztoc19872_1" id="eztoc19872_1"></a><h2>Etude de cas : un filtre par années, et par mois-années</h2> <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-facettes-par-dates/19883-1-fre-FR/eZ-Find-Facettes-par-dates.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-facettes-par-dates/19883-1-fre-FR/eZ-Find-Facettes-par-dates_medium.png" width="113" height="200" style="border: 0px;" alt="eZ Find - Facettes par dates" title="eZ Find - Facettes par dates" /> </a> </p></div><p>L'exemple étudié a surtout une valeur pédagogique, puisqu'il s'agit d'un besoin générique et relativement simple à implémenter. Les listes d'actualités, ou les listes de billets sur les Blogs proposent généralement des <b>filtres par années (2010) ou par mois / année (Janvier 2010)</b> (comme sur ce blog par exemple dans la colonne de droite). Habituellement, pour ce genre de filtre on développe un <a href="http://ezpedia.org/ez/template_operators" target="_blank">opérateur de template</a> permettant d'effectuer la requête SQL nécessaire, ce qui peut rapidement devenir très complexe. <b>Il suffit de lire le code de l'opérateur de template <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezwebin%2Ftrunk%2Fpackages%2Fezwebin_extension%2Fezextension%2Fezwebin%2Fautoloads%2Fezarchive.php" target="_blank">eZArchive</a> pour en comprendre les limites</b>.</p><p>Il est relativement fréquent que ces manipulations SQL souffrent de carences fonctionnelles, comme la propagation des droits, la gestion des langues, la gestion de certaines subtilités entre <b>MySql</b> ou <b>PostGreSql</b>. Ce sont des problématiques à la charge du développeur, puisque l'on contourne les API pour exploiter directement du SQL. Par ailleurs, l'opérateur <b><a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezwebin%2Ftrunk%2Fpackages%2Fezwebin_extension%2Fezextension%2Fezwebin%2Fautoloads%2Fezarchive.php" target="_blank">eZArchive</a></b> montre une autre limite importante, puisqu'il se contente de travailler sur la date de publication '<b>publication_date</b>' (par facilité), et ne permet donc pas d'exploiter <b>un attribut de date spécifique à la classe</b>.</p><a name="eztoc19872_2" id="eztoc19872_2"></a><h2>Développer le filtre par années, et par mois-années avec eZ Find</h2><a name="eztoc19872_2_1" id="eztoc19872_2_1"></a><h3>Etape 1 : Indexer les années, mois / année vers Solr</h3><p>Les <b>settings</b> d'<b>eZ Find</b> (<a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Ftrunk%2Fextension%2Fezfind%2Fsettings%2Fezfind.ini" target="_blank">ezfind.ini</a>, à surcharger dans le <b>ezfind.ini.append.php</b> de votre extension) permettent de déléguer le traitement de l'indexation d'un <b>datatype eZ Publish</b> vers une classe <b>PHP</b> :</p> <pre class="ini"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>SolrFieldMapSettings<span style="">&#93;</span></span> CustomMap<span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>ezdate<span style="">&#93;</span></span>=<span style="color: #660066;">ezfSolrDocumentFieldDate</span> &nbsp;</pre><p>Notre classe <b>PHP</b>, nommée arbitrairement <b>ezfSolrDocumentFieldDate</b> hérite de la classe <b><a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Ftrunk%2Fextension%2Fezfind%2Fclasses%2Fezfsolrdocumentfieldbase.php" target="_blank">ezfSolrDocumentFieldBase</a></b> et doit être ajoutée dans le dossier <b>/extension/myextension/classes/ezfsolrdocumentfielddate.php</b> avec le squelette suivante :</p> <pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000000; font-weight: bold;">class</span> ezfSolrDocumentFieldDate <span style="color: #000000; font-weight: bold;">extends</span> ezfSolrDocumentFieldBase <span style="color: #66cc66;">&#123;</span> <span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.php.net/static"><span style="color: #000066;">static</span></a> <span style="color: #000000; font-weight: bold;">function</span> getFieldName<span style="color: #66cc66;">&#40;</span> eZContentClassAttribute <span style="color: #0000ff;">$classAttribute</span>, <span style="color: #0000ff;">$subAttribute</span> = <span style="color: #000000; font-weight: bold;">null</span>, <span style="color: #0000ff;">$context</span> = <span style="color: #ff0000;">'search'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #808080; font-style: italic;">// return the fieldname like : attr_mydate_d</span> <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getData<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #808080; font-style: italic;">// return the array keys (fieldname =&gt; value), like : array('attr_mydate_dt' =&gt; '2010-04-30T00:00:00Z')</span> <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span> &nbsp;</pre><a name="eztoc19872_3" id="eztoc19872_3"></a><h2>Le rôle de la méthode getFieldName</h2><p>Cette méthode est invoquée pour transformer les noms des attributs <b>eZ Find</b> vers les noms de champs <b>Solr</b>. Ainsi lorsqu'on construit une facette avec la syntaxe '<b>mycontentclass/mydateattribute</b>', cette méthode reçoit '<b>mydateattribute</b>' et doit retourner '<b>attr_mydateattribute_dt</b>'. Nous allons donc implémenter cette fonction de la façon suivante :</p> <ul> <li>Si un sous attribut est spécifié (par exemple '<b>mycontentclass/mydateattribute/year</b>'), alors retourne le nom composé du sous attribut</li> <li>Si aucun sous attribut n'est spécifié, alors exécute le code de la classe parent</li> <li><b>Important : </b>Pour profiter d'une certaine généricité, et éviter de nommer '<b>en dur</b>' les champs <b>Solr</b>, nous utilisons les méthodes parents <b>generateSubattributeFieldName</b> et <b>generateAttributeFieldName</b></li> </ul> <pre class="php">const DEFAULT_SUBATTRIBUTE_TYPE = <span style="color: #ff0000;">'date'</span>; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.php.net/static"><span style="color: #000066;">static</span></a> <span style="color: #000000; font-weight: bold;">function</span> getFieldName<span style="color: #66cc66;">&#40;</span> eZContentClassAttribute <span style="color: #0000ff;">$classAttribute</span>, <span style="color: #0000ff;">$subAttribute</span> = <span style="color: #000000; font-weight: bold;">null</span>, <span style="color: #0000ff;">$context</span> = <span style="color: #ff0000;">'search'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #b1b100;">switch</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$classAttribute</span>-&gt;<span style="color: #006600;">attribute</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'data_type_string'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'ezdate'</span> : <span style="color: #66cc66;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$subAttribute</span> and <span style="color: #0000ff;">$subAttribute</span> !== <span style="color: #ff0000;">''</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #808080; font-style: italic;">// A subattribute was passed</span> <span style="color: #b1b100;">return</span> parent::<span style="color: #006600;">generateSubattributeFieldName</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$classAttribute</span>, <span style="color: #0000ff;">$subAttribute</span>, self::<span style="color: #006600;">DEFAULT_SUBATTRIBUTE_TYPE</span> <span style="color: #66cc66;">&#41;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #808080; font-style: italic;">// return the default field name here.</span> <span style="color: #b1b100;">return</span> parent::<span style="color: #006600;">generateAttributeFieldName</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$classAttribute</span>, self::<span style="color: #006600;">getClassAttributeType</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$classAttribute</span>, <span style="color: #000000; font-weight: bold;">null</span>, <span style="color: #0000ff;">$context</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">break</span>; <span style="color: #000000; font-weight: bold;">default</span>: <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">break</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span> &nbsp;</pre><a name="eztoc19872_4" id="eztoc19872_4"></a><h2>Le rôle de la méthode getData</h2><p>Cette méthode est invoquée pour extraire les données d'<b>eZ Publish</b>, et les préparer pour leur indexation vers <b>Solr</b>. C'est donc dans cette méthode que l'on peut ajouter nos champs supplémentaires '<b>year</b>' et '<b>yearmonth</b>'. Pour faciliter la future exploitation de ces champs avec <b>eZ Find</b>, je souhaite pouvoir construire des facettes ou des filtres selon la syntaxe classique :</p> <ul> <li>'<b>mycontentclass/mydateattribute/year</b>', dont la transposition <b>Solr</b> serait '<b>subattr_date-year_dt</b>'</li> <li>'<b>mycontentclass/mydateattribute/yearmonth</b>', dont la transposition <b>Solr</b> serait '<b>subattr_date-yearmonth_dt</b>'</li> </ul> <pre class="php"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getData<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$contentClassAttribute</span> = <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">ContentObjectAttribute</span>-&gt;<span style="color: #006600;">attribute</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'contentclass_attribute'</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$contentClassAttribute</span>-&gt;<span style="color: #006600;">attribute</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'data_type_string'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'ezdate'</span> : <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$returnArray</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// Get timestamp attribute value</span> <span style="color: #0000ff;">$value</span> = <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">ContentObjectAttribute</span>-&gt;<span style="color: #006600;">metaData</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// Generate the main filedName attr_XXX_dt </span> <span style="color: #0000ff;">$fieldName</span> = parent::<span style="color: #006600;">generateAttributeFieldName</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$contentClassAttribute</span>, self::<span style="color: #006600;">DEFAULT_ATTRIBUTE_TYPE</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #0000ff;">$returnArray</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$fieldName</span><span style="color: #66cc66;">&#93;</span> = parent::<span style="color: #006600;">convertTimestampToDate</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$value</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #808080; font-style: italic;">// Generate the yearmonth subattribute filedName subattr_year_dt</span> <span style="color: #0000ff;">$fieldName</span> = parent::<span style="color: #006600;">generateSubattributeFieldName</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$contentClassAttribute</span>, <span style="color: #ff0000;">'year'</span>, self::<span style="color: #006600;">DEFAULT_SUBATTRIBUTE_TYPE</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #0000ff;">$year</span> = <a href="http://www.php.net/date"><span style="color: #000066;">date</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Y&quot;</span>, <span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// Get Year value : 2010</span> <span style="color: #0000ff;">$returnArray</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$fieldName</span><span style="color: #66cc66;">&#93;</span> = parent::<span style="color: #006600;">convertTimestampToDate</span><span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/strtotime"><span style="color: #000066;">strtotime</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$year</span>.<span style="color: #ff0000;">'-01-01'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #808080; font-style: italic;">// Generate the yearmonth subattribute filedName subattr_yearmonth_dt</span> <span style="color: #0000ff;">$fieldName</span> = parent::<span style="color: #006600;">generateSubattributeFieldName</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$contentClassAttribute</span>, <span style="color: #ff0000;">'yearmonth'</span>, self::<span style="color: #006600;">DEFAULT_SUBATTRIBUTE_TYPE</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #0000ff;">$month</span> = <a href="http://www.php.net/date"><span style="color: #000066;">date</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;n&quot;</span>, <span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// Get Month value : 3</span> <span style="color: #0000ff;">$returnArray</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$fieldName</span><span style="color: #66cc66;">&#93;</span> = parent::<span style="color: #006600;">convertTimestampToDate</span><span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/strtotime"><span style="color: #000066;">strtotime</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$year</span>.<span style="color: #ff0000;">'-'</span>.<span style="color: #0000ff;">$month</span>.<span style="color: #ff0000;">'-01'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>; <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$returnArray</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">break</span>; &nbsp; <span style="color: #000000; font-weight: bold;">default</span>: <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">break</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span> &nbsp;</pre><p><b>A noter :</b> <b>$returnArray</b> contient un tableau à clés, dont voici un exemple de sortie (effectuer avec <a href="http://php.net/manual/fr/function.var-dump.php" target="_blank">var_dump</a>) :</p> <pre class="ini">array<span style="">&#40;</span><span style="">3</span><span style="">&#41;</span> <span style="">&#123;</span> <span style="">&#91;</span><span style="color: #933;">&quot;attr_date_dt&quot;</span><span style="">&#93;</span>=&gt; string<span style="">&#40;</span><span style="">24</span><span style="">&#41;</span> <span style="color: #933;">&quot;2008-12-28T00:00:00.000Z&quot;</span> <span style="">&#91;</span><span style="color: #933;">&quot;subattr_date-year_dt&quot;</span><span style="">&#93;</span>=&gt; string<span style="">&#40;</span><span style="">24</span><span style="">&#41;</span> <span style="color: #933;">&quot;2008-01-01T00:00:00.000Z&quot;</span> <span style="">&#91;</span><span style="color: #933;">&quot;subattr_date-yearmonth_dt&quot;</span><span style="">&#93;</span>=&gt; string<span style="">&#40;</span><span style="">24</span><span style="">&#41;</span> <span style="color: #933;">&quot;2008-12-01T00:00:00.000Z&quot;</span> <span style="">&#125;</span> &nbsp;</pre><p><b>A noter : Solr</b> utilise le format de date <a href="http://fr.wikipedia.org/wiki/ISO_8601" target="_blank">ISO 8601</a>, du type '2010-04-30T00:00:00Z'. La classe parent <b><a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Ftrunk%2Fextension%2Fezfind%2Fclasses%2Fezfsolrdocumentfieldbase.php" target="_blank">ezfSolrDocumentFieldBase</a></b> propose la méthode <b>convertTimestampToDate()</b> pour convertir un format <a href="http://fr.wikipedia.org/wiki/Timestamp" target="_blank">timestamp</a> vers un format <a href="http://fr.wikipedia.org/wiki/ISO_8601" target="_blank">ISO 8601</a>.</p><a name="eztoc19872_5" id="eztoc19872_5"></a><h2>Le template de construction des facettes</h2><p>Nos données par années et par mois-année sont maintenant disponibles. Il ne reste plus qu'à construire nos facettes avec la syntaxe habituelle :</p> <pre class="eztemplate"><span style="color: #D36900;">&#123;</span>def <span style="">$search_yearmonth</span>=<a href="http://ez.no/doc/content/advancedsearch?SearchText=fetch"><span style="color: #008000;">fetch</span></a><span style="color: #D36900;">&#40;</span> ezfind, search, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span> query , <span style="color: #ff0000;">''</span>, <span style="color: #ff0000;">'facet'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span> <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'field'</span>, <span style="color: #ff0000;">'billet/date/year'</span>, <span style="color: #ff0000;">'sort'</span>, <span style="color: #ff0000;">'alpha'</span>, <span style="color: #ff0000;">'limit'</span>, <span style="color: #cc66cc;">20</span> <span style="color: #D36900;">&#41;</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'field'</span>, <span style="color: #ff0000;">'billet/date/yearmonth'</span>, <span style="color: #ff0000;">'sort'</span>, <span style="color: #ff0000;">'alpha'</span>, <span style="color: #ff0000;">'limit'</span>, <span style="color: #cc66cc;">20</span> <span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'class_id'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'billet'</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'subtree_array'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> &nbsp; <span style="color: #D36900;">&#123;</span>def <span style="">$search_extras_year</span>=<span style="">$search_yearmonth</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchExtras'</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">nameList</span>|reverse<span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$search_extras_yearmonth</span>=<span style="">$search_yearmonth</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchExtras'</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">nameList</span>|reverse<span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$date_count</span> = <span style="color: #cc66cc;">0</span> <span style="">$date_ts</span> = <span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#125;</span> &nbsp; &lt;li id=&quot;blog_block_10&quot; class=&quot;colonne_block&quot;&gt; &lt;h1&gt;Archives par années :&lt;/h1&gt; &lt;ul class=&quot;<span style="color: #D36900;">&#123;</span><span style="">$current_css</span><span style="color: #D36900;">&#125;</span> list&quot;&gt; <span style="color: #D36900;">&#123;</span>foreach <span style="">$search_extras_year</span> as <span style="">$facetID</span> =&<a href="http://ez.no/doc/content/advancedsearch?SearchText=gt"><span style="color: #0600FF;">gt</span></a>; <span style="">$datevalue</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=set"><span style="color: #0600FF;">set</span></a> <span style="">$date_count</span> = <span style="">$search_yearmonth</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchExtras'</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">countList</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=set"><span style="color: #0600FF;">set</span></a> <span style="">$date_ts</span> = <span style="">$datevalue</span>|strtotime<span style="color: #D36900;">&#125;</span> &lt;li&gt;&lt;a href=<span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=concat"><span style="color: #804040;">concat</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'/Blogs/(year)/'</span>,<span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%Y'</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span>|ezurl<span style="color: #D36900;">&#125;</span> title=&quot;Archives : <span style="color: #D36900;">&#123;</span><span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%Y'</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> // <span style="color: #D36900;">&#123;</span><span style="">$date_count</span><span style="color: #D36900;">&#125;</span> Billet(s)&quot;&gt;<span style="color: #D36900;">&#123;</span><span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%Y'</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span>&lt;/a&gt;&lt;/li&gt; <span style="color: #D36900;">&#123;</span>/foreach<span style="color: #D36900;">&#125;</span> &lt;/ul&gt; &lt;/li&gt; &lt;li id=&quot;blog_block_11&quot; class=&quot;colonne_block&quot;&gt; &lt;h1&gt;Archives par mois / années :&lt;/h1&gt; &lt;ul class=&quot;<span style="color: #D36900;">&#123;</span><span style="">$current_css</span><span style="color: #D36900;">&#125;</span> list&quot;&gt; <span style="color: #D36900;">&#123;</span>foreach <span style="">$search_extras_yearmonth</span> as <span style="">$facetID</span> =&<a href="http://ez.no/doc/content/advancedsearch?SearchText=gt"><span style="color: #0600FF;">gt</span></a>; <span style="">$datevalue</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=set"><span style="color: #0600FF;">set</span></a> <span style="">$date_count</span> = <span style="">$search_yearmonth</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchExtras'</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">countList</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=set"><span style="color: #0600FF;">set</span></a> <span style="">$date_ts</span> = <span style="">$datevalue</span>|strtotime<span style="color: #D36900;">&#125;</span> &lt;li&gt;&lt;a href=<span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=concat"><span style="color: #804040;">concat</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'/Blogs/(year)/'</span>,<span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%Y'</span> <span style="color: #D36900;">&#41;</span>,<span style="color: #ff0000;">'/(month)/'</span>,<span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%n'</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span>|ezurl<span style="color: #D36900;">&#125;</span> title=&quot;Archives : <span style="color: #D36900;">&#123;</span><span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%F %Y'</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> // <span style="color: #D36900;">&#123;</span><span style="">$date_count</span><span style="color: #D36900;">&#125;</span> Billet(s)&quot;&gt;<span style="color: #D36900;">&#123;</span><span style="">$date_ts</span>|datetime<span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'custom'</span>, <span style="color: #ff0000;">'%F %Y'</span> <span style="color: #D36900;">&#41;</span>|upfirst<span style="color: #D36900;">&#125;</span>&lt;/a&gt;&lt;/li&gt; <span style="color: #D36900;">&#123;</span>/foreach<span style="color: #D36900;">&#125;</span> &lt;/ul&gt; &nbsp; &lt;/li&gt; <span style="color: #D36900;">&#123;</span>undef <span style="">$date_ts</span> <span style="">$date_count</span> <span style="">$search_yearmonth</span> <span style="">$search_extras_yearmonth</span><span style="color: #D36900;">&#125;</span> &nbsp;</pre><p><b>A noter : </b>Le <b>fetch</b> proposé est relativement basique, afin de faciliter la compréhension du mécanisme. Il faut bien sur faire évoluer le code pour obtenir le fonctionnel attendu (utiliser les filtres par exemple), mais ce n'est pas l'objet de ce billet puisque la <a href="http://ez.no/doc/extensions/ez_find/upgrading_to_ez_find_2_2" target="_blank">documentation officielle</a> détaille déjà la façon de procéder.</p><p><b>A noter :</b> le '<b>sort</b>', '<b>alpha</b>' ne permet pas réellement de spécifier que l'on souhaite un tri alphabétique. Il s'agit surtout de spécifier que l'on ne souhaite pas un tri par '<b>count</b>' (nombre d'items associés à la facette). Dans ce cas <b>Solr</b> applique un tri automatique '<b>croissant</b>' en fonction de son index et du type de donnée (ce qui explique l'utilisation de l'opérateur <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/template_operators/arrays/reverse" target="_blank">reverse</a> pour obtenir une liste décroissante).</p> Sun, 16 May 2010 13:30:10 +0000 http://gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-2-Indexer-des-champs-supplementaires-dans-Solr Développement avancé avec eZ Find (partie 1 : La gestion des datatypes entre eZ Find & Solr) <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-1/19768-1-fre-FR/eZ-Find-Chapter-1.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-chapter-1/19768-1-fre-FR/eZ-Find-Chapter-1.png" width="185" height="102" style="border: 0px;" alt="eZ Find - Chapter 1" title="eZ Find - Chapter 1" /> </a> </p></div><p>Après 2 billets un peu &quot;rapides&quot; sur <a href="http://ez.no/ezfind" target="_blank">eZ Find</a> et <a href="http://www.gandbox.fr/Blogs/Technologies-Web/eZ-Find-et-la-gestion-des-datatypes" target="_self">la gestion des datatypes</a>, ainsi que <a href="http://www.gandbox.fr/Blogs/Technologies-Web/eZ-Find-et-ses-utilisations-alternatives-Faire-un-nuage-de-tags" target="_self">l'utilisation des facettes pour construire un nuage de tags</a>, voici le premier billet d'une série de tutoriels à propos d'<a href="http://ez.no/ezfind" target="_blank">eZ Find</a>, qui décrivent plus en détail son fonctionnement et son utilisation avancée dans divers contextes. Cette série de tutoriels introduit <b>quelques nouveautés de la version 2.2</b>, sera traduite progressivement sur le <a href="http://share.ez.no/" target="_blank">share.ez.no</a>, et servira de base pour une conférence de la <a href="http://ez.no/company/ez_conference_awards" target="_blank">eZ Conference 2010</a>, ainsi qu'aux <a href="http://2010.rmll.info/Travailler-avec-eZ-Find-et-SolR.html" target="_blank">Recontres Mondiales du Logiciel Libre 2010</a></p><p><b>Cet article décrit comment <a href="http://ez.no/ezfind" target="_blank">eZ Find</a> transforme et adapte les contenus eZ Publish, et leurs datatypes respectifs pour les indexer dans <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a></b>. <b>La compréhension de ces mécanismes bas niveaux d'eZ Find sont des prérequis indispensables lors des phases de développement et de debug, </b>ne serait ce que pour savoir ou chercher et lire les portions de codes permettant de comprendre le rôle exact d'un settings, d'un paramètre ou d'un filtre.</p><a name="eztoc19760_1" id="eztoc19760_1"></a><h2>Etape 1 : Prérequis avant de démarrer</h2><p>Cet article n'a pas vocation à expliquer à nouveau comment installer et indexer son contenu avec eZ Find. La <a href="http://ez.no/doc/extensions/ez_find/2_2" target="_blank">documentation</a> décrit avec précision les opérations à effectuer. Cependant voici quelques astuces permettant de développer dans de bonnes conditions :</p><a name="eztoc19760_1_1" id="eztoc19760_1_1"></a><h3>Relancer l'indexation du contenu après une modification</h3><p>Il est parfois laborieux de relancer une indexation complète juste pour tester l'impact d'une modification mineure. Alors il existe pour cela quelques paramètres cachés dans le script <b>/bin/php/updatesearchindexsolr.php</b>, qui permettent de désigner un noeud parent de départ, ainsi q'une limite (attention les 3 paramètres combinés sont nécessaires) :</p> <pre class="php">php extension/ezfind/bin/php/updatesearchindexsolr.php --siteaccess=monsiteaccess --topNodeID=<span style="color: #cc66cc;">2546</span> --offset=<span style="color: #cc66cc;">0</span> --limit=<span style="color: #cc66cc;">10</span> &nbsp; &nbsp;</pre><a name="eztoc19760_1_2" id="eztoc19760_1_2"></a><h3>Vérifier ce que Solr a réellement indexé</h3> <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/solr-web-administration/19771-1-fre-FR/Solr-Web-administration.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/solr-web-administration/19771-1-fre-FR/Solr-Web-administration_medium.png" width="200" height="89" style="border: 0px;" alt="Solr - Web administration" title="Solr - Web administration" /> </a> </p></div><p>Pour savoir si vos contenus et vos attributs sont correctement indexés, il suffit d'effectuer une recherche dans l'interface Web d'administration de Solr : <i><b>http://localhost:8983/solr/admin/. </b></i>Cette interface est également utile pour <b>vérifier comment les champs Solr ont été nommés</b>, par exemple sur la version d'<b>eZ Find 2.2</b>, on peut observer 2 champs qui semblent des doublons concernent les titres des articles : <b>attr_title_s</b> et <b>attr_title_t</b>. La suite du billet détaille le comment et le pourquoi de ce comportement.</p><a name="eztoc19760_1_3" id="eztoc19760_1_3"></a><h3>Debug direct avec Solr</h3><p>En laissant une console active, pour pourrez observer les messages envoyés vers <b>Solr</b> de la forme :</p> <pre class="ini">INFO: <span style="">&#91;</span><span style="">&#93;</span> <span style="color: #000099;">webapp</span>=<span style="color: #660066;">/solr path=/select params=<span style="">&#123;</span> ... MESSAGE ... <span style="">&#125;</span> status=<span style="">400</span> QTime=<span style="">5</span></span> &nbsp;</pre> <div class="object-left"> <p> <a href="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-console/19774-1-fre-FR/eZ-Find-Console.png" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/technologie-web/ez-find-console/19774-1-fre-FR/eZ-Find-Console_small.png" width="100" height="61" style="border: 0px;" alt="eZ Find - Console" title="eZ Find - Console" /> </a> </p></div><p>Ce message peut être copier / coller à partir de la console, vers la fin de l'URL dans l'interfaçe d'administration de Solr :<i><b> http://localhost:8983/solr/select/?MESSAGE. </b></i>On obtient ainsi <b>une sortie exacte de ce que Solr envois à eZ Find avant transformation</b>. Cette manipulation est utile lors des phases de Debug, par exemple en manipulant directement le message pour obtenir exactement le résultat attendu.</p><a name="eztoc19760_2" id="eztoc19760_2"></a><h2>Etape 2 : Comment eZ Find pousse le contenu eZ Publish vers Solr</h2><p>Voici le parcours d'exécution du code lors de l'ajout / modification d'un contenu <b>eZ Publish</b> :</p> <ul> <li> Exécution de la méthode <b>registerSearchObject</b>, de la classe <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=nextgen&amp;path=%2Ftrunk%2Fkernel%2Fcontent%2Fezcontentoperationcollection.php" target="_blank">eZContentOperationCollection</a> <br />Si <b>DelayedIndexing</b> activé (voir détail ci dessous) : ajout d'objectID à la table '<b>ezpending_actions</b>' pour un traitement ultérieur</li> <li>Si <b>DelayedIndexing </b>désactivé, fetch de l'objet et transmission de l'objet à la méthode <b>eZSearch::addObject( $object, $needCommit )</b></li> <li><b>Si eZ Find installé et activé</b>, appel de la méthode <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fsearch%2Fplugins%2Fezsolr%2Fezsolr.php" target="_blank"><b>eZSolr::addObject( $contentObject, $commit = true )</b></a></li> <li>Au final, une fois les contenus préparés, appel de la méthode <b>addDocs</b> de la classe<b> <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Ftrunk%2Fextension%2Fezfind%2Fclasses%2Fezsolrbase.php" target="_blank">/extension/ezfind/classes/ezsolrbase.php</a></b>, qui <b>POST</b> ensuite les données via <b>HTTP</b> à l'aide de <a href="http://php.net/manual/fr/ref.curl.php" target="_blank">cURL</a></li> </ul> <a name="eztoc19760_2_4" id="eztoc19760_2_4"></a><h3>eZ Find, un plug-in de recherche</h3><p><b>eZ Find</b> est construit comme un <b>plug-in de recherche</b>, c'est à dire que le module<i> <b>/content/search</b></i><b> </b>a été nativement construit pour être déporté sous forme de plug-in. Ainsi dans l'extension <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fsettings%2Fsite.ini.append.php" target="_blank">/ezfind/settings/site.ini.append.php</a> on trouve la déclaration du plug-in :</p> <pre class="ini"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>SearchSettings<span style="">&#93;</span></span> <span style="color: #000099;">SearchEngine</span>=<span style="color: #660066;">ezsolr</span> &nbsp; &nbsp;</pre><p>C'est ensuite la méthode <a href="http://pubsvn.ez.no/doxygen/4.0/html/ezsearch_8php_source.html#l00399" target="_blank">getEngine()</a> (<i>kernel/classes/ezsearch.php</i>) qui s'occupe d'affecter la bonne classe PHP pour interfacer le plug-in de recherche, à savoir : <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fsearch%2Fplugins%2Fezsolr%2Fezsolr.php" target="_blank">/search/plugins/ezsolr/ezsolr.php</a></p><a name="eztoc19760_2_5" id="eztoc19760_2_5"></a><h3>eZ Find et le mécanisme natif du DelayedIndexing</h3><p>Lors des différentes opérations de mises à jours de contenus, <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fsearch%2Fplugins%2Fezsolr%2Fezsolr.php" target="_blank">la méthode <b>addObject</b> de la classe <b>eZSolr</b></a> sera invoqué. Ce mode de fonctionnement en plug-in permet également d'hériter des autres mécanismes natifs de la recherche<b> eZ Publish</b>, comme par exemple le <b>DelayedIndexing</b>, qui permet de déporter l'indexation (complète ou par classes) vers une tache planifiée : <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=nextgen&amp;path=%2Ftrunk%2Fcronjobs%2Findexcontent.php" target="_blank">indexcontent.php</a> : </p> <pre class="ini"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>SearchSettings<span style="">&#93;</span></span> <span style="color: #000099;">DelayedIndexing</span>=<span style="color: #660066;">disabled|enabled|classbased</span> DelayedIndexingClassList<span style="">&#91;</span><span style="">&#93;</span> DelayedIndexingClassList<span style="">&#91;</span><span style="">&#93;</span>=mycontentclass &nbsp;</pre><p><b>A noter : </b>Cette technique est relativement efficace pour optimiser les temps de réponses Back Office, ou les imports de contenus régulier. Cependant, le <b>DelayedIndexing</b> souffre de quelques limites, puisqu'il est générique (et non optimisé spécifiquement pour <b>eZ Find</b>) et qu'il se contente donc de boucler sur la table '<b>ezpending_actions</b>' afin d'indexer les objets un par un sans se préoccuper des autres finesses de <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a>, comme par exemple l'ajout massif de contenus à indexer, suivi d'un unique '<i>commit</i>'.</p><a name="eztoc19760_3" id="eztoc19760_3"></a><h2>Etape 3 : Le fonctionnement de la méthode addObject</h2><p>La méthode <b>addObject</b> (<a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fsearch%2Fplugins%2Fezsolr%2Fezsolr.php" target="_blank">/search/plugins/ezsolr/ezsolr.php</a>) reçoit :</p> <ul> <li>un unique objet de contenu en paramètre</li> <li>un paramètre optionnel indiquant s'il faut 'commiter' ou non le contenu ajouté (une très bonne façon d'optimiser les indexations massives de contenus)</li> </ul> <p>Cette méthode agit de la façon suivante, dans les grandes lignes :</p> <ul> <li>Vérification s'il faut indexer ou non le contenu, en fonction des classes exclues (settings : [<b>IndexExclude</b>])</li> <li>Récupération des <b>méta données de l'objet</b>, et création des noms et valeurs des champs pour Solr</li> <li>Récupération des <b>méta données des noeuds</b>, et création des noms et valeurs des champs pour Solr</li> <li>Récupération des <b>données des attributs de l'objet</b>, dans chacune des langues, et création des noms et valeurs des champs pour Solr</li> <li>Insertion dans l'index de Solr de l'ensemble des données collectées, en mono ou multicore selon les settings</li> <li><b>Commit final</b>, en fonction du paramètre optionnel de la méthode <b>addObject</b></li> </ul> <p><b>A noter :</b> Depuis <b>eZ Find 2.2</b>, il est possible d'utiliser des 'cores' spécifiques à chaque langues (<i>/extension/ezfind/java/solr.multicore</i>), ce qui permet de dédier des index et des fichiers de configurations spécifiques à chaque langue (spellings.txt, synonmys.txt, stopwords.txt, etc.)</p><a name="eztoc19760_4" id="eztoc19760_4"></a><h2>Etape 4 : Les nommage des champs côté Solr</h2><p> Il est nécessaire de revenir sur <b>la façon dont eZ Find nomme les champs transmis à Solr</b>. Les principales techniques d'exploitations avancées d'<b>eZ Find</b> pour <b>eZ Publish</b> nécessitent de bien comprendre la sémantique et le mécanisme de nommage des champs.<br />C'est la classe <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fclasses%2Fezfsolrdocumentfieldbase.php" target="_blank">/ezfind/classes/ezfsolrdocumentfieldbase.php</a>, ou d'éventuelles classes héritées pour certains datatypes complexes (voir ma contribution <a href="http://svn.projects.ez.no/ezfsolrdocumentfieldobjectrelation/ezfind2.2/ezfsolrdocumentfieldobjectrelation.php" target="_blank">ezfsolrdocumentfieldobjectrelation</a> par exemple) qui a vocation à créer les noms des champs pour <b>Solr</b>, en respectant une sémantique très précise. On obtient ainsi la sémantique suivante :</p><p><b>Le nom des attributs :</b></p> <ul> <li>Nom Solr : <b>attr_[contentattributename]_[contentattributetype], </b>exemple : <b>'attr_title_s'</b>. Il faut noter l'absence de l'identifiant de la classe, ce qui ouvre des perspectives d'exploitation des attributs Solr pour <b>filtrer plusieurs classes sur des attributs homonymes</b> (l'objet d'un prochain billet).</li> <li> Mapping dans un Fetch eZ Find (filtre par exemple) : <b>[contentclassname]/[contentattributename]/[contentsubattributename]</b>, par exemple <b>'article/title'</b>. <br />Le nom de la classe <b>'article'</b> est utilisé comme un filtre supplémentaire lors de la construction de la requête</li> <li>Le <b>'title'</b> est tranformé en <b>'attr_title_s'</b>, le <b>_s</b> étant déduit de settings eZ Find (voir ci-dessous)</li> </ul> <p><b>Le nom des métadonnées :</b></p> <ul> <li>Nom Solr : <b>meta_[metadataname]_[metadatatype]</b>, exemple : <b>meta_class_identifier_s</b></li> <li>Mapping dans un Fetch eZ Find (tri par exemple) : usage interne, par exemple pour un tri par 'class_identifier'</li> </ul> <p><b>Le nom des sous-attributs (inexploité par défaut) :</b></p> <ul> <li>Nom Solr :<b> subattr_[contentattributename]-[contentsubattributename]_[contentsubattributetype]</b>, example : <b>subattr_relatedimage-alttext_s</b></li> </ul> <p><b>Nativement, les sous attributs sont peu ou pas exploités. C'est par contre un formidable outil pour étendre le fonctionnement d'eZ Find et indexer des champs supplémentaire</b>. Voir par exemple ma contribution : <a href="http://projects.ez.no/ezfsolrdocumentfieldobjectrelation" target="_blank">ezfsolrdocumentfieldobjectrelation</a>, qui indexe tous les attributs des objets en relations, en les stockant dans des sous attributs, ce qui permet ensuite d'effectuer toutes les opérations nécessaires sur ces sous attributs (recherche, filtre, facettes), selon la syntaxe <b>'myclass/myattribute/mysubattribute'</b>. Les prochains billets détailleront comment exploiter ce mécanisme pour bien d'autres usages.</p><a name="eztoc19760_5" id="eztoc19760_5"></a><h2>Etape 5 : La gestion des types de champs côté eZ Find</h2><p> Dans les noms de champs <b>Solr</b>, <b>la dernière information désigne le type de champs</b>, et donc comment Solr va devoir considérer l'information (entre un string, un texte, une date, un tableau, etc.)<br />Coté eZ Find, cette définition se fait comme toujours dans les settings. <b>Depuis eZ Find 2.2, il est maintenant possible de définir un type de champs spécifique à chaque contexte d'utilisation :</b></p> <ul> <li><b>DatatypeMap[] : </b>le setting global, s'appliquant à tous les contextes par défaut</li> <li><b>DatatypeMapSort[] :</b> settings spécifique pour les tris</li> <li><b>DatatypeMapFacet[] :</b> settings spécifique pour les facettes</li> <li><b>DatatypeMapFilter[] :</b> settings spécifique pour les filtres</li> </ul> <p>Par exemple, par défaut, dans la version actuelle d'eZ Find 2.2, les attributs de type 'textline' sont définis différemment pour les tris :</p> <ul> <li><b>DatatypeMap[ezstring]=text</b></li> <li><b>DatatypeMapSort[ezstring]=string</b></li> </ul> <p>L'impact au niveau de <b>Solr</b>, c'est que tous les attributs de type 'textline' auront systématiquement 2 champs de correspondance :</p> <ul> <li><b>attr_title_t</b> (utilisé pour la recherche, les facettes et les filtres)</li> <li><b>attr_title_s</b> (utilisé pour les tris)</li> </ul> <p><b>A noter :</b> il est conseillé d'utiliser également le type '<b>string</b>' pour les facettes, afin de considérer le caractère espace comme un caractère lambda, et ainsi obtenir des facettes de type '<b>ma facette</b>', plutôt que '<b>ma</b>' et '<b>facette</b>'.</p><a name="eztoc19760_6" id="eztoc19760_6"></a><h2>Etape 6 : La gestion des types de champs côté Solr</h2><p> <b>Solr</b> possède un fichier de configuration permettant à <b>eZ Find</b> de lui spécifier que le <b>'_s'</b> signifie un <b>string</b>, le <b>'_t'</b> un <b>texte</b>, etc. Il s'agit du fichier <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezfind%2Fezp4%2Fstable%2F2.2%2Fextension%2Fezfind%2Fjava%2Fsolr%2Fconf%2Fschema.xml" target="_blank">/ezfind/java/solr/conf/schema.xml</a><br />Ce fichier de configuration contient la définition d'un certain nombre de noms de champs en dur (pour les meta-données par exemple), mais définie également les correspondances pour tous les noms de champs dynamiques (nos fameux attributs de classes <b>eZ Publish</b>) :</p> <pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_i&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;int&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_f&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;float&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_d&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;double&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_si&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;sint&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_sf&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;sfloat&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_sd&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;sdouble&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_s&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">termVectors</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_sl&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;slong&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_l&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;long&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_t&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">termVectors</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_b&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;boolean&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_dt&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;date&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_random&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;random&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_k&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;keyword&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_lk&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;lckeyword&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="color: #808080; font-style: italic;">&lt;!-- some trie-coded dynamic fields for faster range queries --&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_ti&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;tint&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_tl&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;tlong&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_tf&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;tfloat&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_td&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;tdouble&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_tdt&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;tdate&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="color: #808080; font-style: italic;">&lt;!-- geopoint for geospatial/location searches, boosting, ... --&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;dynamicField</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;*_gpt&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;geopoint&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> &nbsp;</pre><p><b>Ce fichier permet aussi de définir des comportements plus complexes sur certains datatypes eZ Publish</b>, comme par exemple les mots clés (<b>keyword</b>). On y trouve par exemple 2 types de champs différents pour la gestion des keywords ('<b>keyword</b>' pour un respect de la casse et '<b>lckeyword</b>' pour une casse en lowercase), qui peuvent etre exploité indifféremment au niveau d'eZ Find (<b>DatatypeMap</b>).</p> <pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;fieldtype</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;lckeyword&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TextField&quot;</span> <span style="color: #000066;">positionIncrementGap</span>=<span style="color: #ff0000;">&quot;100&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;index&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.PatternTokenizerFactory&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;, *&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TrimFilterFactory&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.LowerCaseFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.RemoveDuplicatesTokenFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/analyzer<span style="font-weight: bold; color: black;">&gt;</span></span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;query&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.PatternTokenizerFactory&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;, *&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TrimFilterFactory&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.SynonymFilterFactory&quot;</span> <span style="color: #000066;">synonyms</span>=<span style="color: #ff0000;">&quot;synonyms.txt&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">expand</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.LowerCaseFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.RemoveDuplicatesTokenFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/analyzer<span style="font-weight: bold; color: black;">&gt;</span></span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/fieldtype<span style="font-weight: bold; color: black;">&gt;</span></span></span> &nbsp;</pre><p>La définition des keywords est riche d'enseignement sur la configuration de Solr. On peut observer le fonctionnement des appels des <b>filtres Solr</b>, et comment sont traités les séparations de mots par des virgules (<b>PatternTokenizerFactory</b>), la gestion de la casse (<b>LowerCaseFilterFactory</b>), ou encore la suppression des doublons (<b>RemoveDuplicatesTokenFilterFactory</b>), etc.</p> Sun, 09 May 2010 13:07:06 +0000 http://gandbox.fr/Blogs/Technologies-Web/Developpement-avance-avec-eZ-Find-partie-1-La-gestion-des-datatypes-entre-eZ-Find-Solr eZ Find et ses utilisations alternatives : Faire un nuage de tags <div class="object-left"> <p> <a href="http://ez.no/ezfind" target="_blank"> <img src="http://www.gandbox.fr/var/plain_site/storage/images/media/images/ez-find-logo/19256-1-fre-FR/eZ-Find-Logo.png" width="183" height="32" style="border: 0px;" alt="eZ Find Logo" title="eZ Find Logo" /> </a> </p></div><p><b><a href="http://ez.no/ezfind" target="_blank">eZ Find</a> est une extension native d'eZ Publish</b>, maintenant disponible dans les diverses installations du <b>CMS</b>. Mon précédent billet donne une courte définition du fonctionnement d'<b>eZ Find</b>, de son couplage avec <b>Solr</b>, et de sa relation avec les <b>datatypes</b>.</p><p><b>eZ Find</b> est généralement présenté et vendu comme un moteur de recherche, et les utilisateurs (et développeurs) peuvent donc s'attendre à un mécanisme du type :</p> <ul> <li>Je saisie une expression libre</li> <li>J'envoie ma recherche</li> <li>J'obtiens une liste de résultat, et j'applique quelques tris (alphabétique, dates, pertinence) et quelques filtres disponibles (par rubriques, par <a href="http://fr.wikipedia.org/wiki/Classification_%C3%A0_facettes" target="_blank">facettes</a>, etc.) </li> </ul> <p><b>Cependant, le cadre d'exploitation d'eZ Find est plus vaste que ce schéma fonctionnel. Ce billet décrit un cas d'utilisation certes relativement inutile mais signification d'une utilisation alternative d'eZ Find : construire un nuage de tags</b>.</p><p>A partir d'un exemple simple, on peut facilement en déduire d'autres cas d'utilisation qui facilitent énormément le développement de certains projets, comme par exemple les agrégateurs de contenus, les portails et autres mécanismes de navigations complexes dans un catalogue.</p><a name="eztoc19248_1" id="eztoc19248_1"></a><h2>Comment construire un nuage de tags sur eZ Publish ? </h2><p>La seule méthode un peu optimisée et fonctionnelle de procéder actuellement est l'utilisation d'un <a href="http://ezpedia.org/ez/template_operators" target="_blank">opérateur de template</a> qui explore la base de données, et notamment la table <b>ezkeyword</b>. Le package <a href="http://ez.no/download/ez_publish/ez_publish_4_stable_releases/4_0/packages/4_0_3" target="_blank">ezwebin</a> propose l'opérateur <b>eztagcloud</b>, qui est facile à déployer et à utiliser.</p> <ul> <li>Voici <b>un exemple d'appel de l'opérateur dans un template</b></li> </ul> <pre class="eztemplate">&lt;div&gt; <span style="color: #D36900;">&#123;</span>eztagcloud<span style="color: #D36900;">&#40;</span> <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span> <span style="color: #ff0000;">'class_identifier'</span>, <span style="color: #ff0000;">'billet'</span>, <span style="color: #ff0000;">'parent_node_id'</span>, <span style="color: #cc66cc;">2</span> <span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> &lt;/div&gt; &nbsp;</pre> <ul> <li>Voici <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezwebin%2Ftrunk%2Fpackages%2Fezwebin_extension%2Fezextension%2Fezwebin%2Fautoloads%2Feztagcloud.php" target="_blank">le code de l'opérateur eztagcloud</a></li> <li>Voici <a href="http://pubsvn.ez.no/websvn2/filedetails.php?repname=ez_extensions&amp;path=%2Fezwebin%2Ftrunk%2Fpackages%2Fezwebin_extension%2Fezextension%2Fezwebin%2Fdesign%2Fezwebin%2Ftemplates%2Ftagcloud%2Ftagcloud.tpl" target="_blank">le code du template tagcloud.tpl</a> associé à l'opérateur (que l'on peut donc surcharger)</li> </ul> <a name="eztoc19248_1_1" id="eztoc19248_1_1"></a><h3>Avantages de l'opérateur</h3><p>Les <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/template_fetch_functions" target="_blank">fonctions fetch natives</a> ne permettent pas de lister un ensemble de keywords en fonction des paramètres utiles (subtree, classes, etc.), c'est donc la seule façon &quot;économique&quot; et &quot;optimisée&quot; de procéder. <b>Les opérateurs permettent souvent aux développeurs eZ Publish avancés d'optimiser certains traitements</b>, en économisant le nombre de requêtes SQL par exemple, ou en facilitant certains algorithmes laborieux à transposer avec le langage de template (par exemple le calcul des pourcentages des styles CSS inline dans cet opérateur)</p><a name="eztoc19248_1_2" id="eztoc19248_1_2"></a><h3>Inconvénients de l'opérateur</h3><p><b>L'écriture de ce type d'opérateur est peu accessible aux développeurs occasionnels</b>, et la manipulation du SQL est une pratique dangereuse si le modèle de données eZ Publish est mal maîtrisé (prise en compte des versions, des visibilités, des langues, des droits...). Par ailleurs cet opérateur encapsule la logique algorithmique du calcul des pourcentages transmis au &quot;<i>font-size</i>&quot; en style inline. Les amoureux du CSS full externe, ou de l'accessibilité devront donc adapter cet opérateur à leur besoin.</p><a name="eztoc19248_2" id="eztoc19248_2"></a><h2>Comment construire un nuage de tags avec eZ Find ? </h2><a name="eztoc19248_2_3" id="eztoc19248_2_3"></a><h3>Comprendre le concept de facettes</h3><p>Derrière ce terme &quot;géométrique&quot; se cache un concept finalement assez simple et naturel, que l'on pourrait appeler : &quot;<b>groupement des résultats pour un champs</b>&quot;, à savoir : </p> <ul> <li>Supposons qu'un résultat de recherche contienne 100 billets</li> <li>Sur ces 100 billets, on peut lister 20 mots clés distincts associés</li> <li>Parmi ces 20 mots clés, le mot clés A est associé à 10 billets, le mot clés B est associé à 5 billets, et ainsi dessuite </li> </ul> <p>On peut transposer cet exemple sur tous les attributs et meta données d'une classe (name, dates, auteur, attribut quelconque), et même obtenir N listes de facettes sur N attributs et méta différents </p><a name="eztoc19248_2_4" id="eztoc19248_2_4"></a><h3>Construite le nuage de mots clés avec des facettes </h3><p>Cet exemple de code montre comment construire sa requête <b>eZ Find</b>, récupérer les <b>facettes</b> résultantes sur l'attribut &quot;<i>tags</i>&quot; de type &quot;<a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/datatypes/keywords" target="_blank">keywords</a>&quot;, et gérer le poids des keywords en fonction d'un algorithme simplifié (j'ai un peu triché sur cet aspect, puisque ce n'est pas l'objet de la démonstration). </p> <pre class="eztemplate"><span style="color: #D36900;">&#123;</span>def <span style="">$search_keywords</span>=<a href="http://ez.no/doc/content/advancedsearch?SearchText=fetch"><span style="color: #008000;">fetch</span></a><span style="color: #D36900;">&#40;</span> ezfind , search, <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span> query , <span style="color: #ff0000;">''</span>, <span style="color: #ff0000;">'facet'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span> <a href="http://ez.no/doc/content/advancedsearch?SearchText=hash"><span style="color: #804040;">hash</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'field'</span>, <span style="color: #ff0000;">'billet/tags'</span>, <span style="color: #ff0000;">'sort'</span>, <span style="color: #ff0000;">'alpha'</span>, <span style="color: #ff0000;">'limit'</span>, <span style="color: #cc66cc;">100</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'class_id'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'billet'</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'filter'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'not'</span>, <span style="color: #ff0000;">'billet/tags:&quot;&quot;'</span><span style="color: #D36900;">&#41;</span>, <span style="color: #ff0000;">'subtree_array'</span>, <a href="http://ez.no/doc/content/advancedsearch?SearchText=array"><span style="color: #804040;">array</span></a><span style="color: #D36900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$search_extras_keywords</span>=<span style="">$search_keywords</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchExtras'</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$search_count_keywords</span>=<span style="">$search_keywords</span><span style="color: #D36900;">&#91;</span><span style="color: #ff0000;">'SearchCount'</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> &nbsp; &lt;li id=&quot;blog_block_<span style="color: #D36900;">&#123;</span><span style="">$bloc_count</span><span style="color: #D36900;">&#125;</span>&quot; class=&quot;colonne_block&quot;&gt; &lt;h1&gt;Tags ezfind :&lt;/h1&gt; &lt;div class=&quot;tagclouds <span style="color: #D36900;">&#123;</span><span style="">$current_css</span><span style="color: #D36900;">&#125;</span>&quot;&gt; <span style="color: #D36900;">&#123;</span>foreach <span style="">$search_extras_keywords</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">nameList</span> as <span style="">$facetID</span> =&<a href="http://ez.no/doc/content/advancedsearch?SearchText=gt"><span style="color: #0600FF;">gt</span></a>; <span style="">$name</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$keyword_count</span> = <span style="">$search_extras_keywords</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">countList</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$percent</span> = <span style="">$keyword_count</span>|div<span style="color: #D36900;">&#40;</span> <span style="">$search_count_keywords</span> <span style="color: #D36900;">&#41;</span>|mul<span style="color: #D36900;">&#40;</span> <span style="color: #cc66cc;">200</span> <span style="color: #D36900;">&#41;</span>|floor|sum<span style="color: #D36900;">&#40;</span> <span style="color: #cc66cc;">100</span> <span style="color: #D36900;">&#41;</span> <span style="color: #D36900;">&#125;</span> &lt;a href=<span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=concat"><span style="color: #804040;">concat</span></a><span style="color: #D36900;">&#40;</span> <span style="">$root_blog_node</span>.<span style="color: #006600;">url_alias</span>, <span style="color: #ff0000;">'/(tag)/'</span>, <span style="">$name</span> <span style="color: #D36900;">&#41;</span>|ezurl<span style="color: #D36900;">&#40;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> style=&quot;font-size: <span style="color: #D36900;">&#123;</span><span style="">$percent</span><span style="color: #D36900;">&#125;</span>%&quot; title=&quot;<span style="color: #D36900;">&#123;</span><span style="">$keyword_count</span><span style="color: #D36900;">&#125;</span> billets taggés '<span style="color: #D36900;">&#123;</span><span style="">$name</span><span style="color: #D36900;">&#125;</span>' // &quot;&gt;<span style="color: #D36900;">&#123;</span><span style="">$name</span>|wash<span style="color: #D36900;">&#40;</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span>&lt;/a&gt;, <span style="color: #D36900;">&#123;</span>undef <span style="">$percent</span><span style="color: #D36900;">&#125;</span> &nbsp; <span style="color: #D36900;">&#123;</span>/foreach<span style="color: #D36900;">&#125;</span> &nbsp; &lt;/div&gt; &lt;/li&gt; <span style="color: #D36900;">&#123;</span>undef <span style="">$search_extras_keywords</span> <span style="">$search_keywords</span> <span style="">$search_count_keywords</span><span style="color: #D36900;">&#125;</span> &nbsp;</pre><a name="eztoc19248_3" id="eztoc19248_3"></a><h2>Quelques astuces &amp; clés de compréhensions</h2> <ul> <li><b>La recherche sur une chaine vide (query , '')</b> est une technique permettant d'explorer l'ensemble des contenus indexés, en appliquant uniquement les filtres et limitations utiles (<i>class_id</i>, <i>subtree_array</i> par exemple)</li> <li>L'opérateur '<b>NOT</b>' n'est pas natif et nécessite <a href="http://www.stuffandcontent.com/2009/10/adding-negative-filters-to-ez-find.html" target="_blank">un petit '<i>hack</i>' proposé par Bruce Morrison</a>, qui sera sans doute disponible dans les futures versions d'eZ Find</li> <li><b>Par défaut les facettes sur des datatypes 'keywords' sont présentés en minuscule</b>. Ce n'est pas un bug, mais une fonctionnalité visant à homogénéiser la <i>casse</i> sur les syntaxes similaires (eZ Publish, ez Publish, Ez Publish, etc.). Cependant lorsqu'on est confiant dans la qualité de sa saisie (puisqu'on utilise <a href="http://projects.ez.no/ezkeyword_autocomplete" target="_blank">une extension d'autocomplétion</a> par exemple), il peut être souhaitable de ne pas forcer l'utilisation du minuscule. Pour cela il faut désactiver le filtre <i>solr.LowerCaseFilterFactory</i> dans le fichier<b> <i>/extension/ezfind/java/solr/conf/schema.xml</i></b></li> </ul> <pre class="xml"><span style="color: #009900;"><span style="color: #808080; font-style: italic;">&lt;!-- eZ Find: This field type is dedicated to ez publish keywords. --&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;fieldtype</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keyword&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TextField&quot;</span> <span style="color: #000066;">positionIncrementGap</span>=<span style="color: #ff0000;">&quot;100&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;index&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.PatternTokenizerFactory&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;, *&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TrimFilterFactory&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="color: #808080; font-style: italic;">&lt;!--&lt;filter class=&quot;solr.LowerCaseFilterFactory&quot;/&gt;</span></span>--&gt; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.RemoveDuplicatesTokenFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/analyzer<span style="font-weight: bold; color: black;">&gt;</span></span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;query&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.PatternTokenizerFactory&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;, *&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TrimFilterFactory&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.SynonymFilterFactory&quot;</span> <span style="color: #000066;">synonyms</span>=<span style="color: #ff0000;">&quot;synonyms.txt&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">expand</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.LowerCaseFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.RemoveDuplicatesTokenFilterFactory&quot;</span><span style="font-weight: bold; color: black;">/&gt;</span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/analyzer<span style="font-weight: bold; color: black;">&gt;</span></span></span> <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/fieldtype<span style="font-weight: bold; color: black;">&gt;</span></span></span> &nbsp;</pre> Mon, 22 Feb 2010 23:11:18 +0000 http://gandbox.fr/Blogs/Technologies-Web/eZ-Find-et-ses-utilisations-alternatives-Faire-un-nuage-de-tags My gandbox.fr's slides talk from the 2010 eZ Community Day in Geneva <p>On <b>2010 January 21</b>, for the <a href="http://share.ez.no/blogs/ez/community-day-at-the-ez-international-winter-conference-2010-in-geneva" target="_blank">eZ Community Day in Geneva</a>, i <i><b>tried</b></i> to tanslate in english language some of my &quot;<b>french</b>&quot; blog posts i write on <a href="http://www.gandbox.fr/" target="_self">http://www.gandbox.fr</a>. There is my &quot;<b><i>english</i></b>&quot; slides from this talk :</p> <ul> <li><a href="/content/download/3380/19094/version/1/file/100116_eZCommunity_Widget_V1.0.pdf" target="_self" class="download">Download the PDF version (1.6 Mo)</a></li> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/My-gandbox.fr-s-slides-talk-from-the-2010-eZ-Community-Day-in-Geneva#slideshare" target="_self">Slideshare version</a></li> </ul> <a name="eztoc19098_1" id="eztoc19098_1"></a><h2>List of the french blog post i used for my talk</h2><p><b>Working with Google Maps :</b></p> <ul> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Ma-cave-sur-eZ-Publish-Google-Maps-Partie-3" target="_self">Ma cave sur eZ Publish : Google Maps (Partie 3)</a></li> </ul> <p><b>Building an UWA Widget (Netvibes / iGoogle) :</b></p> <ul> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Faire-un-Widget-Netvibes-iGoogle-avec-UWA-AJAX-eZ-Publish-Introduction-a-UWA-Partie-1" target="_self">Faire un Widget Netvibes &amp; iGoogle avec UWA, AJAX &amp; eZ Publish : Introduction à UWA (Partie 1)</a></li> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Faire-un-Widget-Netvibes-iGoogle-avec-UWA-AJAX-eZ-Publish-La-couche-eZ-Publish-Partie-2" target="_self">Faire un Widget Netvibes &amp; iGoogle avec UWA, AJAX &amp; eZ Publish : La couche eZ Publish (Partie 2)</a></li> </ul> <p><b>Building a custom RSS</b> :</p> <ul> <li><a href="http://www.gandbox.fr/Blogs/Technologies-Web/Un-flux-RSS-par-Keyword-ou-autre-sur-eZ-Publish" target="_self">Un flux RSS par Keyword (ou autre) sur eZ Publish</a></li> </ul> <a name="eztoc19098_2" id="eztoc19098_2"></a><h2> <a name='slideshare'></a>Slideshare presentation</h2><div class="video"> <object width="600" height="450" type="application/x-shockwave-flash" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=100116ezcommunitywidgetv1-0-100124102940-phpapp02&amp;rel=0&amp;stripped_title=ez-community-gandboxfr"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=100116ezcommunitywidgetv1-0-100124102940-phpapp02&amp;rel=0&amp;stripped_title=ez-community-gandboxfr"></param> <param name="allowfullscreen" value="true"></param> </object> </div> Sun, 24 Jan 2010 21:08:13 +0000 http://gandbox.fr/Blogs/Technologies-Web/My-gandbox.fr-s-slides-talk-from-the-2010-eZ-Community-Day-in-Geneva eZ Find et la gestion des datatypes <p>J'ai publié une &quot;mini&quot; <b><a href="http://projects.ez.no/ezfsolrdocumentfieldobjectrelation" target="_blank">contribution sur la gestion des relations d'objet(s) dans eZ Find</a></b>. Cette contribution est relativement confidentielle (exploitation marginale), mais constitue une bonne occasion pour présenter <b>le fonctionnement d'<a href="http://ez.no/ezfind" target="_blank">eZ Find</a> et sa relation avec les <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/datatypes" target="_blank">datatypes</a></b>. <b><a href="http://ez.no/ezfind" target="_blank">eZ Find</a></b> est une extension encore sous exploitée, alors qu'elle constitue une avancée majeure d'eZ Publish sur la cible &quot;<b>système d'information professionnel</b>&quot;, au côté des extensions <a href="http://projects.ez.no/ezsi" target="_blank"><b>EZSI</b></a> ou encore <b><a href="http://projects.ez.no/nxc_cmis_client" target="_blank">CMIS</a></b>.</p><p><b><a href="http://projects.ez.no/ezfsolrdocumentfieldobjectrelation" target="_blank">Voir la page du projet ezfsolrdocumentfieldobjectrelation</a></b></p><a name="eztoc19035_1" id="eztoc19035_1"></a><h2>eZ Find en quelques mots &quot;faciles à comprendre&quot;</h2> <ul> <li><a href="http://ez.no/ezfind" target="_blank">eZ Find</a> est une &quot;<b>interface</b>&quot; entre eZ Publish (le CMS) et <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> (le moteur de recherche)</li> <li><a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> est un moteur de recherche autonome, qui s'exécute comme un service JAVA, et qui fonctionne en mode <a href="http://fr.wikipedia.org/wiki/Representational_state_transfer" target="_blank">REST</a>, à savoir : <ul> <li>Lors d'une publication, <b>eZ Find</b> prépare le contenu dans une URL et le &quot;pousse&quot; vers <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> (HTTP)</li> <li>Lors d'une recherche (full text, filtres, <a href="http://fr.wikipedia.org/wiki/Classification_%C3%A0_facettes" target="_blank">facettes</a>), <b>eZ Find</b> prépare la question dans une URL et demande à <b>eZ Find</b> la réponse</li> </ul> </li> </ul> <p>Toutes ces opérations complexes sont &quot;<b>masquées</b>&quot; pour le développeur, qui doit uniquement se soucier de bien formuler ses requêtes dans son habituel <b>langage de template</b> : <i>fecth( ezfind, search, params...)</i>. La puissance d'<b>eZ Find</b> réside dans cette simplicité d'exploitation, au profit de le puissance fonctionnelle de <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> et des &quot;questions&quot; que l'on peut formuler, notamment sur la pertinence (façon <a href="http://www.google.fr/" target="_blank">google</a>) ou sur les classifications à facettes.</p><a name="eztoc19035_2" id="eztoc19035_2"></a><h2>eZ Find est les datatypes</h2><p><b>eZ Publish</b> fonctionne sur le concept de &quot;<a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/datatypes" target="_blank">datatype</a>&quot;, à savoir des <b>types de données &quot;riches&quot;</b> permettant de représenter des lignes de textes, des numériques, des dates, mais aussi des types de données plus complexes ou exotiques comme des images, des vidéos, des relations d'objet(s) ou de la géolocalisation. eZ Publish permet également de définir <b>ses propres datatypes</b>, on peut donc comprendre que les correspondances entre les types de données <b>eZ Publish</b> et les types de données <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> nécessite quelques paramétrages, selon 2 cas de figures :</p> <ul> <li>Les correspondances de données parfaitement symétriques : <b>ligne de texte = string</b></li> <li>Les correspondances de données &quot;<b>sur mesure</b>&quot; : <b>relations d'objets</b> (et gestion des sous attributs)</li> </ul> <p>Pour définir ces correspondances <b>eZ Find</b> propose un fichier de paramétrage <i><b>extension/ezfind/settings/ezfind.ini</b></i></p><a name="eztoc19035_3" id="eztoc19035_3"></a><h2>Fonctionnement de la classe ezfSolrDocumentFieldObjectRelation</h2><p>L'aspect &quot;<b>sur mesure</b>&quot; de la correspondance entre les <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/reference/datatypes" target="_blank">datatypes</a> eZ Publish et les <b>types de données eZ Find </b>implique un &quot;point de vue&quot; de développement dans la façon de gérer les cas particuliers et complexes. L'indexation des relations d'objets multiples est une bonne illustration de l'éternel dilemme du développeur : &quot;<b>jusqu'où faut-il aller ?</b>&quot;</p><a name="eztoc19035_3_1" id="eztoc19035_3_1"></a><h3>Comportement natif de ezfSolrDocumentFieldObjectRelation</h3><p>Tous les objets en relation permettent de générer un unique champs &quot;text&quot; par concaténation de tous les attributs de tous les objets. On obtient ainsi un contenu indexé de type &quot;<i>objet1/attribut1 objet1/attribut2 objet2/attribut1 objet2/attribut2</i>&quot;. Cette logique est tout à fait adaptée à la recherche &quot;full text&quot;, mais inadaptée à l'exploitation de <a href="http://fr.wikipedia.org/wiki/Classification_%C3%A0_facettes" target="_blank">facette</a>. Pour un objet en relation dont le &quot;<i>name</i>&quot; est &quot;<b>mon objet en relation</b>&quot;, on obtient les facettes suivantes sur &quot;<i>myclass/myattribute</i>&quot; :</p> <ul> <li>&quot;<b>mon</b>&quot; (10 résultats)</li> <li>&quot;<b>objet</b>&quot; (3 résultats)</li> <li>&quot;<b>en</b>&quot; (30 résultats)</li> <li>&quot;<b>relation</b>&quot; (5 résultats)</li> </ul> <a name="eztoc19035_3_2" id="eztoc19035_3_2"></a><h3>Comportement de l'évolution ezfSolrDocumentFieldObjectRelation</h3><p>La gestion des facettes devient possible, en spécifiant un attribut en particulier ou alors en invoquant le &quot;<i>name</i>&quot;. La page du projet montre <a href="http://projects.ez.no/ezfsolrdocumentfieldobjectrelation" target="_blank">quelques exemples de codes basiques</a>. En exploitant l'exemple précédent, on obtient alors l'unique facette suivante :</p> <ul> <li>&quot;<b>mon objet en relation</b>&quot; (3 résultats)</li> </ul> <a name="eztoc19035_4" id="eztoc19035_4"></a><h2>Gestion des filtres de type string</h2><p>Un fois les facettes générées, il est nécessaire de construire le lien permettant de filtrer les résultats par &quot;<b>mon objet en relation</b>&quot;. eZ Find (ou plutôt <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a>) exige logiquement que les chaînes de caractères (string) soient encapsulées par des &quot;<b>doubles côtes</b>&quot;.</p><p>Cet extrait de code (un peu complexe) montre comment étendre le <b><i>search.tpl</i></b> pour générer des filtres pour les chaînes de caractères : filtres par &quot;<b>text line</b>&quot;, &quot;<b>keywords</b>&quot; ou &quot;<b>relation d'objet(s)</b>&quot;</p> <pre class="eztemplate"><span style="color: #D36900;">&#123;</span>foreach <span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">nameList</span> as <span style="">$facetID</span> =&<a href="http://ez.no/doc/content/advancedsearch?SearchText=gt"><span style="color: #0600FF;">gt</span></a>; <span style="">$name</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>if <span style="">$name</span>|trim|count_chars|gt<span style="color: #D36900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> &lt;li&gt; <span style="color: #D36900;">&#123;</span>if <span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">field</span>|compare<span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">'facet_fields'</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$url_link</span> = <a href="http://ez.no/doc/content/advancedsearch?SearchText=concat"><span style="color: #804040;">concat</span></a><span style="color: #D36900;">&#40;</span><span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">queryLimit</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span>|explode<span style="color: #D36900;">&#40;</span><span style="color: #ff0000;">':'</span><span style="color: #D36900;">&#41;</span>.<span style="color: #cc66cc;">0</span>,<span style="color: #ff0000;">':&quot;'</span>,<span style="">$name</span>|urlencode,<span style="color: #ff0000;">'&quot;'</span><span style="color: #D36900;">&#41;</span><span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>else<span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>def <span style="">$url_link</span> = <span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">queryLimit</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span>|wash<span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>/if<span style="color: #D36900;">&#125;</span> &lt;a title=&quot;<span style="color: #D36900;">&#123;</span><span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">countList</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span> Réponse(s) trouvée(s) dans les '<span style="color: #D36900;">&#123;</span><span style="">$name</span>|wash<span style="color: #D36900;">&#125;</span>' // &quot; href=<span style="color: #D36900;">&#123;</span><a href="http://ez.no/doc/content/advancedsearch?SearchText=concat"><span style="color: #804040;">concat</span></a><span style="color: #D36900;">&#40;</span> <span style="">$baseURI</span>, <span style="color: #ff0000;">'&amp;facet_field='</span>, <span style="">$facetField</span>|wash, <span style="color: #ff0000;">'&amp;filter[]='</span>, <span style="">$url_link</span> <span style="color: #D36900;">&#41;</span>|ezurl<span style="color: #D36900;">&#125;</span>&gt;<span style="color: #D36900;">&#123;</span><span style="">$name</span>|wash<span style="color: #D36900;">&#125;</span>&lt;/a&gt; (<span style="color: #D36900;">&#123;</span><span style="">$search_extras</span>.<span style="color: #006600;">facet_fields</span><span style="color: #D36900;">&#91;</span><span style="">$index</span><span style="color: #D36900;">&#93;</span>.<span style="color: #006600;">countList</span><span style="color: #D36900;">&#91;</span><span style="">$facetID</span><span style="color: #D36900;">&#93;</span><span style="color: #D36900;">&#125;</span>) <span style="color: #D36900;">&#123;</span>undef <span style="">$url_link</span><span style="color: #D36900;">&#125;</span> &lt;/li&gt; <span style="color: #D36900;">&#123;</span>/if<span style="color: #D36900;">&#125;</span> <span style="color: #D36900;">&#123;</span>/foreach<span style="color: #D36900;">&#125;</span> &nbsp; &nbsp;</pre><p><b>A noter : </b>L'opérateur <i><b>urlencode</b></i> n'est pas natif (fonction PHP) et doit être déclaré dans <i><b>template.ini.append.php</b></i> :</p> <ul> <li><b>PHPOperatorList[urlencode]=urlencode</b></li> </ul> Wed, 13 Jan 2010 21:33:06 +0000 http://gandbox.fr/Blogs/Technologies-Web/eZ-Find-et-la-gestion-des-datatypes Faire de l'édition frontale AJAX avec eZ Publish & Mootools (Partie 3) <p>Pour terminer cette série de billet (voir la <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Faire-de-l-edition-frontale-AJAX-avec-eZ-Publish-Mootools-Partie-1" target="_self">partie 1</a> et la <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Faire-de-l-edition-frontale-AJAX-avec-eZ-Publish-Mootools-Partie-2" target="_self">partie 2</a>) concernant l'édition frontal <a href="http://fr.wikipedia.org/wiki/Asynchronous_JavaScript_and_XML" target="_blank">AJAX</a> sur <b>eZ Publish</b>, voici des extraits de code et quelques détails de fonctionnement concernant ce qui n'est pas encore décrit à ce stade, à savoir :</p> <ul> <li>La génération de masques de saisie en <a href="http://mootools.net/" target="_blank">mootools</a> (mes fameux <b>custom captions</b>)</li> <li>La couche <b>eZ Publish</b> et la mise à jour des données</li> </ul> <a name="eztoc18316_1" id="eztoc18316_1"></a><h2>Les custom captions en Mootools</h2><p>Comme vue dans le précédent billet, la déclaration de la classe <b>ajaxwebin</b> nécessite de renseigner la propriété <b>caption</b> par l'instance d'une classe spécifique permettant de générer le masque de saisie attendu sur clic d'une zone éditable, comme par exemple :</p><a name="eztoc18316_1_1" id="eztoc18316_1_1"></a><h3>Instance d'une classe pour une liste déroulante</h3> <pre class="javascript"><span style="color: #003366; font-weight: bold;">new</span> ajaxcaptionsSelect<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span> <span style="color: #3366CC;">'minValue'</span>: <span style="color: #CC0000;">0</span>, <span style="color: #3366CC;">'maxValue'</span>: <span style="color: #CC0000;">12</span>, <span style="color: #3366CC;">'setStyles'</span>: <span style="color: #66cc66;">&#123;</span>margin: <span style="color: #3366CC;">'0 -10px'</span>, border: <span style="color: #3366CC;">'1px dotted #000'</span>, background: <span style="color: #3366CC;">'#ffffdd'</span><span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> &nbsp; &nbsp;</pre><a name="eztoc18316_1_2" id="eztoc18316_1_2"></a><h3>Instance d'une classe pour un champs de saisie</h3> <pre class="javascript"><span style="color: #003366; font-weight: bold;">new</span> ajaxcaptionsInput<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span> <span style="color: #3366CC;">'setStyles'</span>: <span style="color: #66cc66;">&#123;</span>border: <span style="color: #3366CC;">'1px dotted #000'</span>, background: <span style="color: #3366CC;">'#ffffdd'</span><span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span> &nbsp; &nbsp;</pre><a name="eztoc18316_1_3" id="eztoc18316_1_3"></a><h3>Définition de la superclasse et des classes hérités</h3><p>J'aurais pu exploiter diverses techniques pour définir une superclasse <b>ajaxcaptions</b> et ses classes dérivées <b>ajaxcaptionSelect</b> et <b>ajaxcaptionsInput</b>, comme par exemple l'utilisation du mécanisme de <a href="http://fr.wikipedia.org/wiki/Programmation_orient%C3%A9e_prototype" target="_blank">prototype</a> du langage <b>JavaScript</b>. J'ai opté pour le plus scolaire <a href="http://mootools.net/docs/core/Class/Class#Class:implement" target="_blank">implement</a>, qui reste le plus facile à manipuler dans l'esprit de <a href="http://mootools.net/" target="_blank">mootools</a>.</p><p>Le principe est trivial, il s'agit de déclarer une classe, en spécifiant que l'ensemble des propriétés et des méthodes d'une autre classe sont à dupliquer. Rien n'empêche par la suite d'exploiter ou de mixer dans l'exécution du code des évolutions du <a href="http://fr.wikipedia.org/wiki/Programmation_orient%C3%A9e_prototype" target="_blank">prototype</a> des objets, ou encore d'invoquer à nouveau la méthode <a href="http://mootools.net/docs/core/Class/Class#Class:implement" target="_blank">implement</a> dynamiquement.</p><p><b>Ce formalisme a pour avantage d'être facilement compréhensible (assez scolaire), et facilement extensible :</b></p> <pre class="javascript"><span style="color: #009900; font-style: italic;">// Classe abstraite de génération d'éléments xHTML</span> <span style="color: #003366; font-weight: bold;">var</span> ajaxcaptions = <span style="color: #003366; font-weight: bold;">new</span> <span style="color: #003366; font-weight: bold;">Class</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span> Implements: <span style="color: #66cc66;">&#91;</span>Options<span style="color: #66cc66;">&#93;</span>, &nbsp; options: <span style="color: #66cc66;">&#123;</span> minValue: <span style="color: #CC0000;">0</span>, maxValue: <span style="color: #CC0000;">0</span>, setStyles: <span style="color: #003366; font-weight: bold;">null</span>, myElement: <span style="color: #003366; font-weight: bold;">null</span> <span style="color: #66cc66;">&#125;</span>, <span style="color: #009900; font-style: italic;">// Constructeur de la classe</span> initialize: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>options<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">setOptions</span><span style="color: #66cc66;">&#40;</span>options<span style="color: #66cc66;">&#41;</span>; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">process</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #66cc66;">&#125;</span>, <span style="color: #009900; font-style: italic;">// Retourne le caption</span> getElement: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #009900; font-style: italic;">// Classe de génération xHTML d'un 'select-one', contenant des valeurs de minValue à maxValue</span> <span style="color: #003366; font-weight: bold;">var</span> ajaxcaptionsSelect = <span style="color: #003366; font-weight: bold;">new</span> <span style="color: #003366; font-weight: bold;">Class</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span> Implements: ajaxcaptions, process: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> &nbsp; <span style="color: #003366; font-weight: bold;">var</span> myElement; myElement = <span style="color: #003366; font-weight: bold;">new</span> Element<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'select'</span><span style="color: #66cc66;">&#41;</span>; myElement.<span style="color: #006600;">setStyles</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">setStyles</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #66cc66;">&#40;</span>i=<span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">minValue</span>; i&lt;=<span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">maxValue</span>; i++<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> myElement.<span style="color: #006600;">adopt</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> Element<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'option'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">set</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'text'</span>, i<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span> = myElement; <span style="color: #66cc66;">&#125;</span>, getValue: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span>.<span style="color: #006600;">selectedIndex</span>; <span style="color: #66cc66;">&#125;</span>, setValue: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span>.<span style="color: #006600;">selectedIndex</span> = value; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #009900; font-style: italic;">// Classe de génération xHTML d'un 'input'</span> <span style="color: #003366; font-weight: bold;">var</span> ajaxcaptionsInput = <span style="color: #003366; font-weight: bold;">new</span> <span style="color: #003366; font-weight: bold;">Class</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span> Implements: ajaxcaptions, process: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> &nbsp; <span style="color: #003366; font-weight: bold;">var</span> myElement; myElement = <span style="color: #003366; font-weight: bold;">new</span> Element<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'input'</span><span style="color: #66cc66;">&#41;</span>; myElement.<span style="color: #006600;">setStyles</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">setStyles</span><span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span> = myElement; <span style="color: #66cc66;">&#125;</span>, getValue: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span>.<span style="color: #006600;">value</span>; <span style="color: #66cc66;">&#125;</span>, setValue: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">myElement</span>.<span style="color: #006600;">value</span> = value; <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>; &nbsp; &nbsp;</pre><a name="eztoc18316_2" id="eztoc18316_2"></a><h2>La couche eZ Publish de mise à jour des données</h2><p>Comme décrit dans le <a href="http://www.gandbox.fr/Blogs/Technologies-Web/Faire-de-l-edition-frontale-AJAX-avec-eZ-Publish-Mootools-Partie-2" target="_self">précédent billet</a>, l'appel des <b>URL eZ Publish</b> correspond au motif suivant : <b>/ajaxwebin/action/[<i>attribute_id</i>]/[<i>object_id</i>]/[<i>value</i>]</b> :</p> <pre class="javascript"><span style="color: #003366; font-weight: bold;">var</span> url = <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">ajaxmodule</span> + <span style="color: #3366CC;">'/'</span> + <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">options</span>.<span style="color: #006600;">attributeID</span> + <span style="color: #3366CC;">'/'</span> + object_id + <span style="color: #3366CC;">'/'</span> + value; &nbsp; &nbsp;</pre> <ul> <li><b>ajaxmodule</b> est spécifié en dur dans l'instance des classes <a href="http://mootools.net/" target="_blank">mootools</a>, et correspond à la racine du module, par exemple : <b>/ajaxwebin/action</b></li> <li><b>attributeID </b>est spécifié en dur dans l'instance des classes <a href="http://mootools.net/" target="_blank">mootools</a>, et correspond à l'identifiant <b>eZ Publish</b> du champ à modifier, par exemple <b>stock</b> ou <b>title</b></li> <li><b>object_id </b>est fixé dynamiquement dans les classes CSS, et permet de transmettre l'identifiant (objet_id) de l'objet <b>eZ Publish</b> à modifier</li> <li><b>value</b> correspond à la valeur à appliquer lors de la modification</li> </ul> <a name="eztoc18316_3" id="eztoc18316_3"></a><h2>L'implémentation du module eZ Publish</h2><p>Je ne reviendrai pas sur l'implémentation du module qui est déjà abordé en détail sur plusieurs articles, comme par exemple le <a href="http://ezpedia.org/en/ez/module" target="_blank">tutoriel de module d'eZPedia</a>.</p><a name="eztoc18316_3_4" id="eztoc18316_3_4"></a><h3>Quelques précisions concernant le code</h3> <ul> <li>La méthode de modification est la plus classique, mais il aurait été possible d'utiliser la méthode <b>fromString</b> (<a href="http://www.lifeissheet.info/2009/07/17/modification-des-valeurs-dattibuts-dun-object-ezpublish/" target="_blank">voir le billet de Mox</a>), ou encore l'expérimental <b>kernelwrapper</b> et sa classe <b>ezpObject</b> (mais ce sera pour un prochain billet)</li> <li><b>A noter :</b> L'utilisation de la méthode <a href="http://pubsvn.ez.no/doxygen/4.1/html/classeZContentCacheManager.html#28963decd313fdec93602147ce0f914d" target="_blank">clearObjectViewCache</a>, qui permet de <b>forcer le rafraîchissement de tous les caches impactés par la modification de l'objet</b> (selon les différentes directives, dont le <a href="http://ez.no/doc/ez_publish/technical_manual/4_x/features/view_caching/smart_view_cache_cleaning" target="_blank">Smartviewcache</a>)</li> </ul> <a name="eztoc18316_3_5" id="eztoc18316_3_5"></a><h3>Code du module eZ Publish de modification de l'objet</h3> <pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #0000ff;">$Module</span> = <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">&quot;Module&quot;</span><span style="color: #66cc66;">&#93;</span>; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'action'</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$action</span> = <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'action'</span><span style="color: #66cc66;">&#93;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$action</span> = <span style="color: #ff0000;">''</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'object'</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$object_id</span> = <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'object'</span><span style="color: #66cc66;">&#93;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$object_id</span> = <span style="color: #000000; font-weight: bold;">null</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'value'</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$value</span> = <span style="color: #0000ff;">$Params</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'value'</span><span style="color: #66cc66;">&#93;</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$value</span> = <span style="color: #000000; font-weight: bold;">null</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #0000ff;">$Result</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #0000ff;">$Result</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'path'</span><span style="color: #66cc66;">&#93;</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #0000ff;">$Result</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'pagelayout'</span><span style="color: #66cc66;">&#93;</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #0000ff;">$Result</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'content'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #ff0000;">''</span>; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$action</span> != <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #66cc66;">&#40;</span>!<a href="http://www.php.net/is_null"><span style="color: #000066;">is_null</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$object_id</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> &amp;&amp; <span style="color: #66cc66;">&#40;</span>!<a href="http://www.php.net/is_null"><span style="color: #000066;">is_null</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> &nbsp; <span style="color: #0000ff;">$object</span> = eZContentObject::<span style="color: #006600;">fetch</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$object_id</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$object</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$data_map</span> = <span style="color: #0000ff;">$object</span>-&gt;<span style="color: #006600;">attribute</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'data_map'</span> <span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$data_map</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$action</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$attribute</span> = <span style="color: #0000ff;">$data_map</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$action</span><span style="color: #66cc66;">&#93;</span>; &nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$data_map</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$action</span><span style="color: #66cc66;">&#93;</span>-&gt;<span style="color: #006600;">DataTypeString</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'ezinteger'</span>: <span style="color: #0000ff;">$attribute</span>-&gt;<span style="color: #006600;">setAttribute</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'data_int'</span>, <span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #b1b100;">break</span>; <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'ezstring'</span>: <span style="color: #0000ff;">$attribute</span>-&gt;<span style="color: #006600;">setAttribute</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'data_text'</span>, <span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #b1b100;">break</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #0000ff;">$attribute</span>-&gt;<span style="color: #006600;">sync</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; eZContentCacheManager::<span style="color: #006600;">clearObjectViewCache</span><span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$object_id</span> <span style="color: #66cc66;">&#41;</span>; <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #0000ff;">$value</span>; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">''</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">''</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #66cc66;">&#125;</span> &nbsp; eZDB::<span style="color: #006600;">checkTransactionCounter</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; eZExecution::<span style="color: #006600;">cleanExit</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; &nbsp; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span> <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">''</span>; <span style="color: #66cc66;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">?&gt;</span> &nbsp; &nbsp;</pre> Wed, 07 Oct 2009 21:23:50 +0000 http://gandbox.fr/Blogs/Technologies-Web/Faire-de-l-edition-frontale-AJAX-avec-eZ-Publish-Mootools-Partie-3