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

<channel>
	<title>Restons Zend &#187; Zend Framework</title>
	<atom:link href="https://blog.developpez.com/lucas-corbeaux/pcategory/php/zend-framework/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/lucas-corbeaux</link>
	<description></description>
	<lastBuildDate>Fri, 18 Jan 2013 12:02:26 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Présentation de mon site personnel maitre-corbeaux.com</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p11216/php/site_personnel_maitre_corbeaux</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p11216/php/site_personnel_maitre_corbeaux#comments</comments>
		<pubDate>Mon, 13 Aug 2012 10:26:09 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Depuis janvier 2011, mon (très laid) site http://www.maitre-corbeaux.com/ a été mis en ligne et est alimenté par mon activité Internet. Je consacre cet article à présenter, tardivement, son concept et les raisons de sa création. Édition au 18/01/2013 : Pour pas mal de raison, notamment de temps, le site a été fermé : la mise à jour des API et le faible intérêt que revêtait le projet au final font que cette décision a finalement [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Depuis janvier 2011, mon (très laid) site http://www.maitre-corbeaux.com/ a été mis en ligne et est alimenté par mon activité Internet. Je consacre cet article à présenter, tardivement, son concept et les raisons de sa création.<br />
<span id="more-12"></span><br />
<em><strong>Édition au 18/01/2013</strong> : Pour pas mal de raison, notamment de temps, le site a été fermé : la mise à jour des API et le faible intérêt que revêtait le projet au final font que cette décision a finalement été prise, préférant réserver du temps sur des projets à plus forte valeur ajoutée. Le source reste toutefois disponible sur github.</em></p>
<p><strong>La vitrine de ma veille technologique</strong></p>
<p>Maitre-corbeaux.com, en plus d’un mauvais calembour sur mon patronyme, est un site dont la vocation première est de centraliser en un unique point l’ensemble de mon activité internet liée à ma profession de développeur.</p>
<p>En résumé, tous les quart d’heures sont parcourus un ensemble de « feeds » d’activité (flux RSS, Atom, API diverses dont Twitter…) et mon activité est insérée en base, indexée par Lucene et mise à disposition sur le site. Le but de cette mise à disposition de ma veille technologique est multiple :</p>
<ul>
<li>Pour retrouver facilement l’ensemble des articles et actus que j’ai pu lire. Je suis le premier consommateur de mon site… quelques mauvaises langues disent d’ailleurs que je suis aussi le seul <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></li>
<li>Pour expérimenter certaines choses sur un projet concret mais peu exigeant : depuis sa création, j’ai expérimenté dessus un ORM très basique maison, un moteur de recherche basé sur Zend_Search_Lucene, m’amuser sur certaines API comme Twitter et Pocket…</li>
<li>Et enfin, avoir une présence sur Internet en tant que professionnel du Web, tout en communiquant très clairement sur mon absence totale de goût en terme de design ! Difficile de nier que ma valeur ajoutée ne se trouve pas en front-end…</li>
</ul>
<p><strong>Un site open source</strong></p>
<p>Mais maitre-corbeaux.com n’est pas seulement née de la volonté de diffuser ma veille technologique, le site est également open source, et disponible sur Github : <a href="https://github.com/lucascorbeaux/maitre-corbeaux.com">https://github.com/lucascorbeaux/maitre-corbeaux.com</a></p>
<p>Comme mon flux Github est référencé comme source d’activité, cela signifie que le site auto-publie les évolutions de son propre code source.</p>
<p>Le but de cette diffusion du code source, est de pouvoir mettre à disposition un projet complet et fonctionnel basé sur le Zend Framework, plutôt atypique (pas un énième CMS, moteur de blog, CRM ou e-commerce !), et couvert par les tests unitaires (ce sont également mes premières armes sur PHPUnit que j’ai fait sur ce site à sa création…).</p>
<p><strong>Piste d&rsquo;évolutions</strong></p>
<p>Le site n’a pas connu d’évolution majeure de ses fonctionnalités depuis le départ. Le rythme d’évolution est peu soutenu, et est plus dédié à de petits bugs ponctuels et des améliorations mineures qu’autre chose.</p>
<p>Actuellement, dans l’idée de faire évoluer le site vers ZF2, la couverture de test est en cours d’amélioration. Une fois l’intégralité du site correctement couvert par les tests, la migration (potentiellement lourde et complexe) vers la nouvelle version du framework sera plus sûre…</p>
<p>Tout un tas de pistes d’évolutions sont envisagées, en mode « un jour, peut-être » :</p>
<ul>
<li>Flux RSS.</li>
<li>Possibilité de filtrer les items par source.</li>
<li>Utiliser Google Docs comme backoffice CMS pour le éditer contenu du site.</li>
<li>Autre ?</li>
</ul>
<p><strong>Votre utilisation</strong></p>
<p>Mais alors, à quoi peut bien vous servir maitre-corbeaux.com ?</p>
<ul>
<li>À rechercher dans ma veille technologique via le moteur de recherche intégré. Vous trouverez des articles, le plus souvent intéressants, que j’ai eut l’occasion de lire et de RT. Quelques suggestions de recherche :
<ul>
<li><a href="http://www.maitre-corbeaux.com/search/zend">http://www.maitre-corbeaux.com/search/zend</a></li>
<li><a href="http://www.maitre-corbeaux.com/search/phpunit">http://www.maitre-corbeaux.com/search/phpunit</a></li>
<li><a href="http://www.maitre-corbeaux.com/search/management">http://www.maitre-corbeaux.com/search/management</a></li>
</ul>
</li>
<li>À utiliser tout ou partie du code source du projet pour vos propres besoins… N’hésitez pas à me faire savoir en quoi ce site vous aura été ou non utile.</li>
<li>À observer, critiquer, repenser, un petit projet complet Zend Framework développé par un autre.</li>
<li>Autre ?</li>
</ul>
<p><strong>Votre avis</strong></p>
<p>Alors me direz-vous, pourquoi cet article ? Et bien maintenant que le site a « tourné » un peu il contient pas mal de contenu, et commence à pouvoir être utile aux personnes en recherche d’articles sur des sujets orientés vers le développement Web, alors autant le faire connaître un peu.</p>
<p>Aussi, et surtout, je serais assez content d’avoir des retours, négatifs ou positifs :</p>
<ul>
<li>Sur le concept, si c’est utile, à qui et pourquoi.</li>
<li>Sur la qualité du code, des tests et les choix techniques, ce que vous auriez fait différemment.</li>
<li>Si vous êtes intéressé sur quelques explications sur l’architecture logicielle du site, je pourrais écrire dessus sans soucis, faites-le savoir si c’est le cas.</li>
<li>Sur ce que vous voulez <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></li>
</ul>
<p>Bref, vos commentaires ici, sur Github, sur Twitter, bref où vous voulez, sont les bienvenus. Quelque chose vous serait utile dans l’absolu ? Demandez toujours, si c’est réalisable dans le temps dont je dispose, je pourrais le planifier.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un peu de veille pour le week-end : PHPUnit</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p9975/php/veille_phpunit</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p9975/php/veille_phpunit#comments</comments>
		<pubDate>Sun, 15 May 2011 00:16:20 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Bien que l’intérêt de couvrir son application par des tests unitaires soit indiscutable, le processus n’est souvent pas naturel pour le développeur PHP, bien ancré dans des habitudes de développement. Je n’ai moi-même franchis le cap que récemment, et le but de ce rapide billet est de vous fournir quelques ressources pour vous lancer, ou simplement compléter vos connaissances sur PHPUnit et les tests unitaires de façon plus générale. Tout d’abord, les excellents Webinars de [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bien que l’intérêt de couvrir son application par des tests unitaires soit indiscutable, le processus n’est souvent pas naturel pour le développeur PHP, bien ancré dans des habitudes de développement.</p>
<p>Je n’ai moi-même franchis le cap que récemment, et le but de ce rapide billet est de vous fournir quelques ressources pour vous lancer, ou simplement compléter vos connaissances sur PHPUnit et les tests unitaires de façon plus générale.</p>
<p><span id="more-2"></span></p>
<p>Tout d’abord, les excellents Webinars de Michelangelo van Dam à ce sujet, dont voici les slides :</p>
<p><iframe src="http://www.slideshare.net/slideshow/embed_code/5253168" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="http://www.slideshare.net/DragonBe/unit-testing-after-zf-18" title="Unit testing after Zend Framework 1.8" target="_blank">Unit testing after Zend Framework 1.8</a> </strong> from <strong><a href="http://www.slideshare.net/DragonBe" target="_blank">Michelangelo van Dam</a></strong> </div>
<p>http://joind.in/3381</p>
<p>Cet e-book, gratuit et très intéressant pour se lancer :</p>
<p>http://giorgiosironi.blogspot.com/2009/12/practical-php-testing-is-here.html</p>
<p>Et bien entendu, la documentation de référence, que je vous conseille de lire en entier car c’est une des meilleures documentation qu’il m’ait été donné de lire :</p>
<p>http://www.phpunit.de/manual/3.6/en/index.html</p>
<p>Loin d’être une simple documentation de référence, c’est aussi un guide complet, qui explique pourquoi tester, et qui aborde même le Test Driven Development (TDD).</p>
<p>Pour conclure, même si les tests unitaires peuvent rebuter de prime abord (accroissement du coût de développement initial, impression de se sentir un peu “perdu”, remise en cause très forte de sa méthodologie de travail) les bénéfices se font sentir très vite.</p>
<p>Et pas uniquement au niveau des régressions : tester son code avant même de l’écrire, c’est l’occasion de prendre du recul et de repérer des erreurs de design : si je n’arrive pas à tester mon code, n’est-ce pas parcequ’il y a un couplage un peu trop fort entre ces deux classes ?</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Retours sur le webinar Zend Framework 2 Patterns</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p9850/php/webinar_zend_framework_2_patterns</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p9850/php/webinar_zend_framework_2_patterns#comments</comments>
		<pubDate>Wed, 30 Mar 2011 20:41:10 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ce soir a eut lieu un Webinar dont le thème était les patterns de Zend Framework 2. Matthew Weier O&#8217;Phinney, Lead Project du Zend Framework, nous a présenté ce soir quelques concepts clés sur lesquels s’articuleront le futur ZF2. Sans en faire un résumé complet, les slides et le podcast seront de toutes manières sûrement disponibles d’ici quelques jours, je vais essayer de vous en toucher un mot rapide, car pas mal de choses intéressantes [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Ce soir a eut lieu un Webinar dont le thème était les patterns de Zend Framework 2. Matthew Weier O&rsquo;Phinney, Lead Project du Zend Framework, nous a présenté ce soir quelques concepts clés sur lesquels s’articuleront le futur ZF2.</p>
<p>Sans en faire un résumé complet, les slides et le podcast seront de toutes manières sûrement disponibles d’ici quelques jours, je vais essayer de vous en toucher un mot rapide, car pas mal de choses intéressantes y ont été dites, notamment quelques dates.</p>
<p><span id="more-11"></span></p>
<h3>Quelques dates</h3>
<p>Inutile de faire durer le suspense, quelques estimations de date nous ont été communiquées ce soir. Pour faire court, il est question d’une milestone fin mai, qui sera suivie d’une version de preview.</p>
<p>Plus important : la bêta est prévue pour cet été, quant à la release stable il faudra attendre la fin 2011 si tout va bien.</p>
<h3>Compatibilité</h3>
<p>Sans surprise, la rétro-compatibilité sera cassée par cette version majeure, mais ça on le savait déjà. Ce qui n’est pas tout à fait facile à anticiper, c’est dans quelle mesure ? J’ai cependant bon espoir qu’une application Zend Framework moderne (utilisant Zend_Application) puisse migrer progressivement sans trop de casse.</p>
<h3>Autoloader</h3>
<p>Au niveau de l’autoload, on a revu ce soir quelques unes des informations que l’on avait pu voir traîner ici et là.</p>
<p>Une utilisation massive des namespaces en complément des préfixes actuels est à prévoir, mais là encore ce n’est pas une surprise. La possibilité d’utiliser l’ancien système de préfixe devrait aider à migrer les applications Zend Framework 1.x.</p>
<p>Quoi qu’il en soit, les nouveautés sont très intéressantes, tel que l’autoloader classmap, basé sur un simple tableau associatif de correspondance classe / fichier et donc beaucoup plus performant.</p>
<p>A ce niveau, l’élément qui m’a incontestablement le plus emballé est le remplaçant de l’actuel PluginLoader, à savoir le PluginBroker. Cela se présente comme une interface Broker qui utilise un objet implémentant l’interface ShortNameLocator.</p>
<p>L’implémentation d’un pattern Strategy entre le Broker et le Locator permet de changer ce dernier en cours d’exécution, et donc de modifier dynamiquement la façon dont sont chargées les plugins. Cela permet pas mal de fantaisies, telles que la mise en cache des plugins chargés&#8230; Il semblerait aussi que le mécanisme de chargement des plugins sera plus transparent et facile à appréhender.</p>
<p>Il m’a également semblé que l’exemple PluginBroker qui nous a été montré utilisait un classmap loader, pour des raisons de performances.</p>
<h3>EventManager</h3>
<p>L’EventManager est prévu pour deux utilisations spécifiques :</p>
<ul>
<li>En tant que classe autonome, utilisée par composition conjointement avec une classe pouvant déclencher des évènements.</li>
<li>En tant qu’EventManager statique, un singleton dont l’instance est récupérable partout par l’habituelle méthode statique getInstance().</li>
</ul>
<p>Cette nouveauté m’a beaucoup emballée, et permettra de greffer de nombreux comportements annexes aux classes métiers (logging, vidage de cache&#8230;) sans mélanger le métier et les tâches “utilitaires”. L’utilisation conjointe de Closures et de l’EventManager est très prometteur&#8230;</p>
<p>Une question que je me pose, je ne pense pas que le sujet ait été abordé durant ce Webinar mais j’ai peut-être raté un épisode : ce système d’évènement remplacera-t-il l’actuel fonctionnement des Zend_Controller_Plugin ?</p>
<h3>DependencyInjection</h3>
<p>Difficile de parler de ce point. Pas parcequ’il n’y a pas grand chose à en dire, mais au contraire car il y en aurait beaucoup !</p>
<p>L’utilisation massive de Closures conjointement à un DependencyInjector est réellement pleine de promesse, le DependencyInjector se chargeant de permettre l’accès aux services ainsi que l’interdépendance des services les uns avec les autres.</p>
<p>Un dernier exemple nous a permis d’entrevoir le fonctionnement du futur MVC, ou le dispatcher utilisera un DependencyInjector afin d’associer aux contrôleurs les services qu’ils utilisent, sans pour autant que ne soit chargés les éléments qui ne sont pas utilisés.</p>
<p>Il sera possible de paramétrer le DI soit par programmation, soit par configuration.</p>
<h3>Autres éléments</h3>
<p>Comme évoqué plus haut, ce billet n’est pas un résumé complet&#8230;</p>
<p>Il a entres autres été questions d’une réorganisation des exceptions pour tirer profit <a href="http://php.net/manual/fr/spl.exceptions.php">des exceptions de la SPL</a> plutôt que de les sous-classer par composant. En héritant des exceptions de la SPL et en implémentant des interfaces propres aux composants, il sera possible de définir d’affiner grandement le traitement des exceptions. En espérant que ça permettre de clarifier la détection des erreurs 404 par le plugin errorHandler&#8230;</p>
<p>L’uniformisation de la définition des options a également été évoquée, par l’habituelle méthode setOptions ou par un objet de configuration propre à chaque composant.</p>
<p>Il a enfin été question la refonte du MVC, basée sur trois interfaces “légères” : Request, Response et Dispatchable, la troisième utilisant la première pour générer la seconde.</p>
<h3>En conclusion</h3>
<p>Je suis vraiment très enthousiaste vis à vis de ce qui a été présenté ce soir, et je pense que le prochain Zend Framework a vraiment beaucoup à nous offrir. L’attente va être longue !</p>
<p>Le webinar a été vraiment très instructif et je vous invite à consulter les slides quant ils seront en ligne (probablement à cette adresse d’ici quelques jours, la création d’un compte utilisateur est nécessaire : http://www.zend.com/en/resources/webinars/ ).</p>
<p><ins>Edition du 08/04/2011 :</ins><br />
juste pour vous signaler la mise à disposition du Webinar sur le site de Zend (nécessite une inscription préalable) http://www.zend.com/en/webinar/Framework/70170000000bX3J-webinar-zf-2-patterns-20110330.flv</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mise en place d&#8217;un cache Static avec le Zend Framework</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p9647/php/zend_cache_backend_static_zend_framework</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p9647/php/zend_cache_backend_static_zend_framework#comments</comments>
		<pubDate>Sat, 08 Jan 2011 14:26:05 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Apparu avec le Zend Framework 1.10, le backend de cache Static (Zend_Cache_Backend_Static) est un cache particulièrement agressif, qui permet d&#8217;accéder à des pages de votre application comme si elles étaient de simples fichiers HTML statiques : aucun fichier PHP n&#8217;est appelé, et le gain de rapidité peut être vraiment énorme sur des pages lourdes à générer. Bien entendu, cela n&#8217;est pas sans inconvénients : L&#8217;application Zend Framework n&#8217;étant plus du tout sollicitée, la validité du [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Apparu avec le Zend Framework 1.10, le backend de cache Static (<a href="http://framework.zend.com/manual/en/zend.cache.backends.html#zend.cache.backends.static">Zend_Cache_Backend_Static</a>) est un cache particulièrement agressif, qui permet d&rsquo;accéder à des pages de votre application comme si elles étaient de simples fichiers HTML statiques : aucun fichier PHP n&rsquo;est appelé, et le gain de rapidité peut être vraiment énorme sur des pages lourdes à générer.</p>
<p>Bien entendu, cela n&rsquo;est pas sans inconvénients :</p>
<ul>
<li>L&rsquo;application Zend Framework n&rsquo;étant plus du tout sollicitée, la validité du cache n&rsquo;est pas testée avant affichage, ce qui signifie que le cache doit être vidé via une autre partie de l&rsquo;application (cron job, vidage du cache lors de la modification du contenu&#8230;).</li>
<li>Les pages très dynamiques peuvent être difficiles à mettre en cache, surtout si des fonctionnalités Ajax sont présentes (activer ou non le cache en fonction du contexte, ne pas servir le cache pour les requêtes POST&#8230;).</li>
<li>Les fichiers de cache doivent être accessibles dans le docroot, ce qui rends délicat la mise en cache de contenu à accès restreint.</li>
</ul>
<p>Pour ne rien arranger, la documentation à ce sujet est un peu légère : je n&rsquo;ai par exemple pas trouvé de cas concret de mise en place, et c&rsquo;est ce que je vais tenter de faire maintenant <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /><br />
<span id="more-10"></span><br />
Avant d&rsquo;aller plus loin je tiens a donner un petit avertissement : ce billet tient plus d&rsquo;une compilation d&rsquo;informations au sujet du cache Static que d&rsquo;un véritable tutoriel. Les informations ont été testées tant que possible, mais n&rsquo;ont pas bénéficiées de multiples relectures ou de tests approfondis. L&rsquo;intégralité du code a été testé avec le Zend Framework 1.11.1, et PHP 5.3.3.</p>
<p>Le backend de cache Static est prévu pour fonctionner conjointement avec le frontend Capture. Il utilise également un autre cache pour stocker des métadonnées sur les pages mises en cache, typiquement un cache Core avec un backend File.</p>
<p>Première chose, on va créer un projet vierge :<br />
<code class="codecolorer text default"><span class="text">zf create project static-cache</span></code></p>
<p>Ensuite on va créer une action qui sera mise en cache :<br />
<code class="codecolorer text default"><span class="text">zf create action Cached Index</span></code></p>
<p>Ensuite on va éditer le fichier de configuration pour désactiver le buffer de sortie du FrontController : c&rsquo;est un pré-requis indispensable pour que le cache Static fonctionne.<br />
<code class="codecolorer text default"><span class="text">resources.frontController.params.disableOutputBuffering = 1</span></code></p>
<p>Accessoirement vous pouvez préférer le faire directement dans le code :<br />
<code class="codecolorer text default"><span class="text">$front-&gt;setParam('disableOutputBuffering', true);</span></code></p>
<p>Il nous faut également quelques directives Apache, afin d&rsquo;indiquer au serveur de servir les pages mises en cache en priorité si elles existent. On part du principe que les pages mises en cache sont seront situées dans le dossier cached du docroot. Voici le contenu de mon .htaccess, vous pouvez aussi vous inspirer de celui de la <a href="http://framework.zend.com/manual/en/zend.cache.backends.html#zend.cache.backends.static">documentation du backend static</a> pour définir le votre :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RewriteEngine On <br />
&nbsp;<br />
RewriteCond %{DOCUMENT_ROOT}/cached/index.html -f <br />
RewriteRule ^/?$ cached/index.html [L] <br />
&nbsp;<br />
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.html -f <br />
RewriteRule .* %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.html [L] <br />
&nbsp;<br />
RewriteCond %{REQUEST_FILENAME} -s [OR] <br />
RewriteCond %{REQUEST_FILENAME} -l [OR] <br />
RewriteCond %{REQUEST_FILENAME} -d <br />
RewriteRule ^.*$ - [NC,L] <br />
RewriteRule ^.*$ index.php [NC,L]</div></div>
<p>Vous noterez que ce .htaccess ne gère que les pages d&rsquo;extension html et, si il suffit pour notre exemple, il se montrera très insuffisant pour une véritable application. On remarquera aussi que le cache de la racine du site est géré alors que l&rsquo;action index ne sera pas mise en cache dans notre exemple : en prévoyant le coup dés le début, on s&rsquo;assure de la possibilité de le faire plus tard au besoin.</p>
<p>Maintenant que les bases sont posées, on va mettre un cache static sur l&rsquo;action cached du contrôleur index. On va le faire de deux façons différentes : &laquo;&nbsp;from scratch&nbsp;&raquo; d&rsquo;abord, pour mieux cerner le fonctionnement du frontend Capture, et ensuite en utilisant le Zend_Cache_Manager et l&rsquo;action helper Cache.</p>
<p>Pour activer le cache nous allons remplir la méthode init de notre contrôleur comme suit :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function init() <br />
{ <br />
&nbsp; &nbsp; $tagCache = Zend_Cache::factory('Core', 'File', array('automatic_serialization' =&gt; true), array('cache_dir' =&gt; APPLICATION_PATH . '/../data/cache')); <br />
&nbsp; &nbsp; $cache = Zend_Cache::factory('Capture', 'Static', array(), array('public_dir' &nbsp; =&gt; APPLICATION_PATH . '/../public/cached', <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'tag_cache' &nbsp; =&gt; $tagCache)); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; $actions = array('cached'); <br />
&nbsp;<br />
&nbsp; &nbsp; if (in_array($this-&gt;_request-&gt;getActionName(), $actions)) { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$id = bin2hex($this-&gt;_request-&gt;getRequestUri()); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$cache-&gt;start($id, array()); <br />
&nbsp; &nbsp; } <br />
}</div></div>
<p>On instancie d&rsquo;abord un cache Core avec un backend File pour stocker les métadonnées des pages de cache. Dans notre cas j&rsquo;ai choisis de stocker le cache dans un dossier /data/cache/. A noter également qu&rsquo;il est nécessaire pour le bon fonctionnement du cache d&rsquo;activer le paramètre automatic_serialization.</p>
<p>Une fois que nous avons notre tagCache, nous allons instancier le cache Static : le frontend ne prends aucun paramètre particulier, tandis que le backend attends au moins deux paramètres : le dossier dans lequel stocker les fichiers de cache qui doit être publique (d&rsquo;où le nom du paramètre : public_dir), ainsi que le cache Core pour les métadonnées (tag_cache).</p>
<p>Ensuite on s&rsquo;assure de lancer le cache uniquement sur les actions désirées : dans notre cas uniquement l&rsquo;action cached. On peut ainsi facilement mettre en cache d&rsquo;autres actions en remplaçant la variable $actions :<br />
<code class="codecolorer text default"><span class="text">$actions = array('index', 'cached');</span></code></p>
<p>La méthode start attends 3 paramètres dont 1 optionnel : l&rsquo;id unique du cache, un tableau de tags à lui associer (pour faciliter la maintenance plus tard), et éventuellement une extension a donner au fichier de cache (par défaut ce sera .html). L&rsquo;id unique est généré en récupérant l&rsquo;équivalent hexadécimal de l&rsquo;uri courante, je me suis sur ce point inspiré du code de l&rsquo;action helper Cache (voir plus bas).</p>
<p>Vous pouvez lancer l&rsquo;application et vérifier : l&rsquo;appel de l&rsquo;url /index/cached va générer le fichier html /public/cached/index/cached.html</p>
<p>Si le serveur est bien configuré, c&rsquo;est ce fichier qui sera servit aux visiteurs, et non plus l&rsquo;application.</p>
<p>Bien, maintenant on a vu comment mettre en place le cache Static &laquo;&nbsp;from scratch&nbsp;&raquo;, il est donc temps de voir comment on peut aller beaucoup plus vite&#8230;</p>
<p>Car le Zend Framework offre deux aides précieuses :<br />
* Le Cache Manager, qui permet de configurer vos caches depuis un fichier de configuration et de les récupérer facilement n&rsquo;importe où dans votre application.<br />
* L&rsquo;Action Helper Cache dont le rôle semble dédié au cache Static. Je dis bien semble car en l&rsquo;absence de documentation et / ou de commentaires explicites, c&rsquo;est l&rsquo;interprétation que je fais de son code source.</p>
<p>Le Cache Manager préconfigure un cache Static et son cache de métadonnées sous les clés &lsquo;page&rsquo; (<code class="codecolorer text default"><span class="text">Zend_Cache_Manager::PAGECACHE</span></code>) et &lsquo;pagetag&rsquo; (<code class="codecolorer text default"><span class="text">Zend_Cache_Manager:PAGETAGCACHE</span></code>).</p>
<p>Nous allons donc configurer ces caches depuis notre application.ini :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">resources.cachemanager.page.backend.options.public_dir = APPLICATION_PATH &quot;/../public/cached&quot; <br />
resources.cachemanager.pagetag.backend.options.cache_dir = APPLICATION_PATH &quot;/../data/cache&quot;</div></div>
<p>Et maintenant, nous allons remplacer le code de la méthode init pour utiliser l&rsquo;action helper Cache :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function init() <br />
{ <br />
&nbsp; &nbsp; $this-&gt;_helper-&gt;cache(array('cached')); <br />
}</div></div>
<p>L&rsquo;helper Cache accepte deux autres arguments optionnels : un tableau de tags, et une extension.</p>
<p>Comme vous pouvez le constater, au final le déploiement de ce cache se fait très simplement, mais une recherche préalable est nécessaire pour bien appréhender les différents éléments qui entrent en jeu. J&rsquo;espère que ce billet aidera quelques développeurs à s&rsquo;y retrouver <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /><br />
Si vous avez des questions, ou des remarques, ne vous privez pas !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Form.Validator.List : un petit plugin Mootools pour des erreurs &#171;&#160;Zend_Form-like&#160;&#187; côté client</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p9280/javascript/form_validator_list_plugin_mootools</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p9280/javascript/form_validator_list_plugin_mootools#comments</comments>
		<pubDate>Sat, 11 Sep 2010 15:31:26 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mootools]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Il y a quelques mois, je vous parlais de lier simplement les Form.Validator de Mootools avec Zend_Form. Ayant commencé à étudier le problème (en trois mois, il était temps ), j&#8217;ai en premier lieu avancé sur la problématique côté client : avoir un rendu des erreurs Mootools identique aux erreurs Zend_Form. Vu la lourdeur qu&#8217;implique la modification des Zend_Form_Decorator pour chaque élément, j&#8217;ai pris le partis de minimiser ces modifications en adaptant tant que possible [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Il y a quelques mois, je vous parlais de <a href="http://blog.developpez.com/lucas-corbeaux/p8990/php/zend-framework/zend-form-verification-client-side/">lier simplement les Form.Validator de Mootools avec Zend_Form</a>.</p>
<p>Ayant commencé à étudier le problème (en trois mois, il était temps <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> ), j&rsquo;ai en premier lieu avancé sur la problématique côté client : avoir un rendu des erreurs Mootools identique aux erreurs Zend_Form.<br />
<span id="more-4"></span><br />
Vu la lourdeur qu&rsquo;implique la modification des Zend_Form_Decorator pour chaque élément, j&rsquo;ai pris le partis de minimiser ces modifications en adaptant tant que possible le CSS pour avoir la présentation souhaitée. Cette façon de faire convient pour la majorité des formulaires, ça serait dommage de s&rsquo;en priver&#8230; Sur cette base, je souhaite donc que les validateurs Mootools produisent les même erreurs que mes Zend_Form.</p>
<p>Le fonctionnement du Form.Validator de Mootools est simple : on active la validation pour un formulaire, en affinant le comportement avec quelques options, et l&rsquo;outil détermine les contrôles à effectuer en fonction des classes sur vos champs input : pas de liaison forte entre le client et le serveur, on se contente d&rsquo;attribuer des classes.</p>
<p>Par exemple, prenons ce formulaire :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;form id=&quot;mootools-validator&quot; method=&quot;post&quot; action=&quot;&quot;&gt; <br />
&nbsp; &nbsp;&lt;dl class=&quot;zend_form&quot;&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &lt;dt id=&quot;name-label&quot;&gt;&lt;label for=&quot;name&quot; class=&quot;required&quot;&gt;Name* :&lt;/label&gt;&lt;/dt&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &lt;dd id=&quot;name-element&quot;&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;input type=&quot;text&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;&quot; class=&quot;minLength:3 maxLength:20&quot;&gt; <br />
&nbsp; &nbsp; &nbsp; &lt;/dd&gt; <br />
&nbsp; &nbsp; &nbsp; &lt;dd id=&quot;valid-element&quot;&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;input type=&quot;submit&quot; name=&quot;valid&quot; id=&quot;valid&quot; value=&quot;Valider&quot;&gt; <br />
&nbsp; &nbsp; &nbsp; &lt;/dd&gt; <br />
&nbsp; &nbsp;&lt;/dl&gt; <br />
&lt;/form&gt;</div></div>
<p>Notre champ input a deux classes assez particulière, minLength:3 et maxLength:20, qui vont permettre de vérifier côté client si le champ contient bien un texte entre 3 et 20 caractères.</p>
<p>Pour activer la validation, c&rsquo;est simple, il suffit d&rsquo;instancier Form.Validator :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">window.addEvent('domready', function() { &nbsp;<br />
&nbsp; new Form.Validator('mootools-validator'); <br />
});</div></div>
<p>Dés à présent, les validateurs seront sollicités sur les évènements onBlur (des champs input) et onSubmit (du formulaire).</p>
<p>Le Form.Validator de Mootools ne se charge &laquo;&nbsp;que&nbsp;&raquo; d&rsquo;activer les validateurs et de stocker leur résultat : des évènements sont déclenchés, et il faut les utiliser pour gérer notamment l&rsquo;affichage des erreurs.</p>
<p>Une implémentation plus complète est disponible via Form.Validator.Inline : cette classe permet d&rsquo;afficher chaque erreur dans un bloc div pour chaque champ concerné. Pour l&rsquo;utiliser, il suffit simplement d&rsquo;instancier Form.Validator.Inline au lieu de Form.Validator :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">window.addEvent('domready', function() { &nbsp;<br />
&nbsp; new Form.Validator.Inline('mootools-validator'); <br />
});</div></div>
<p>Pour les intéressés, vous trouverez la documentation ici : </p>
<p>http://mootools.net/docs/more/Forms/Form.Validator</p>
<p>Et là :</p>
<p>http://mootools.net/docs/more/Forms/Form.Validator.Inline</p>
<p>En m&rsquo;inspirant un peu du code source du Form.Validator.Inline, j&rsquo;ai donc conçu une ébauche de Form.Validator.List. Cette classe permet d&rsquo;afficher les erreurs sous forme de liste ul, exactement comme le Zend_Form_Decorator_Errors. De cette manière, je peux alterner contrôles côté client et côté serveur sans que l&rsquo;affichage ne change pour l&rsquo;utilisateur.</p>
<p>Je vous invite à jeter un oeil du côté du code sur le dépôt github :</p>
<p>http://github.com/lucascorbeaux/Form.Validator.List</p>
<p>Lorsque les travaux seront plus avancés et que le code sera mieux testé, je le déposerais sur la forge Mootools afin de toucher un plus large public. Pour ceux qui ne connaissent pas la forge mootools, on y trouve pas mal de plugins utiles et ça se trouve ici : http://mootools.net/forge/</p>
<p><em>Pour la petite histoire, il s&rsquo;agit de ma première approche de github, et de la première fois que j&rsquo;utilise git, n&rsquo;ayant eut pour le moment que l&rsquo;occasion de travailler sur SVN. Plus encore, il s&rsquo;agit de ma première contribution, aussi modeste soit-elle&#8230; Ca fait longtemps que je voulais franchir le cap, c&rsquo;est désormais chose faite ! <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> Plus que jamais, tout commentaire, positif ou négatif, est plus que le bienvenue.</em></p>
<p><ins>Petite update pour signaler la mise en ligne du plugin sur la forge Mootools : http://mootools.net/forge/p/form_validator_list</ins></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ContextSwitch : utilisation de contextes personnalisés</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p9117/php/context_switch_contextes_personnalises</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p9117/php/context_switch_contextes_personnalises#comments</comments>
		<pubDate>Wed, 14 Jul 2010 13:24:31 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Pour faire suite au précédent billet sur ContextSwitch et en attendant de creuser un peu plus avant le sujet de la validation client-side des Zend_Form, je vais vous parler brièvement aujourd’hui de la création de contexte personnalisé. Il ne s’agit pas ici d’apprendre comment créer ses propres contextes. Pour ça je vous renvoie à cette adresse qui s&#8217;acquittera de cette tâche beaucoup mieux que je ne saurais le faire : http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch Ce dont nous allons [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Pour faire suite au <a href="http://blog.developpez.com/lucas-corbeaux/p8744/php/zend-framework/contextswitch-cohabitation-ajaxcontext/">précédent billet sur ContextSwitch</a> et en attendant de creuser un peu plus avant le sujet de la <a href="http://blog.developpez.com/lucas-corbeaux/p8990/php/zend-framework/zend-form-verification-client-side/">validation client-side des Zend_Form</a>, je vais vous parler brièvement aujourd’hui de la création de contexte personnalisé.</p>
<p>Il ne s’agit pas ici d’apprendre comment créer ses propres contextes. Pour ça je vous renvoie à cette adresse qui s&rsquo;acquittera de cette tâche beaucoup mieux que je ne saurais le faire : http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch</p>
<p>Ce dont nous allons parler aujourd’hui, c’est d’un piège dans lequel il est très facile de tomber lorsque l’on utilise un contexte &laquo;&nbsp;maison&nbsp;&raquo; pour la première fois.<br />
<span id="more-8"></span><br />
Vous l’avez sentis venir, faîtes chauffer Zend_Tool car on va créer une nouvelle application. Par manque évident d’imagination, notre application se contentera d’afficher la date et l’heure dans une unique action datetime.</p>
<p>Voici notre contrôleur :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class IndexController extends Zend_Controller_Action <br />
{ &nbsp;<br />
&nbsp; public function datetimeAction() <br />
&nbsp; { <br />
&nbsp; &nbsp; $this-&gt;view-&gt;datetime = Zend_Date::now()-&gt;toString('dd/MM/YYYY HH:mm:ss'); <br />
&nbsp; } <br />
}</div></div>
<p>Notre vue, datetime.phtml :<br />
<code class="codecolorer text default"><span class="text">Nous sommes le : &lt;b&gt;&lt;?php echo $this-&gt;escape($this-&gt;datetime); ?&gt;&lt;/b&gt;</span></code></p>
<p>Vous m’en voudrez si on saute les explications ? Non ? Continuons, alors. Nous avons pour besoin d’afficher notre vue d’une autre façon, simplement sous forme de texte brut. Les deux contextes fournis par défaut par le Zend Framework étant xml et json, nous allons avoir besoin d’un contexte txt.</p>
<p>Nous rajoutons une méthode init à notre contrôleur :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function init() <br />
{ <br />
&nbsp; $this-&gt;_helper <br />
&nbsp; &nbsp; &nbsp;-&gt;contextSwitch <br />
&nbsp; &nbsp; &nbsp;-&gt;addContext('txt', array ('suffix' =&gt; 'txt', <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'headers'=&gt; array('content-type' =&gt; 'text/plain'))) <br />
&nbsp; &nbsp; &nbsp;-&gt;addActionContext('datetime', 'txt') <br />
&nbsp; &nbsp; &nbsp;-&gt;initContext(); <br />
}</div></div>
<p>Rien de très compliqué, on créé un contexte texte avec pour suffixe txt, un content-type défini à text/plain, on associe ce contexte à l’action datetime et on initialise le ContextSwitch.</p>
<p>On créé la vue associée, datetime.txt.phtml :<br />
<code class="codecolorer text default"><span class="text">Nous sommes le : &lt;?php echo $this-&gt;escape($this-&gt;datetime); ?&gt;</span></code></p>
<p>Notre application fonctionne correctement, mais il y a deux problèmes :</p>
<ul>
<li>Le premier soucis, c’est que notre nouveau contexte, txt, est un contexte qui sera tôt ou tard utile ailleurs : il aurait plus sa place quelque part où on pourrait le réutiliser. Admettons que vous êtes sûr à 100% que votre contexte est totalement unique, et laissons en l’état.</li>
<li>Le second soucis est plus sournois, nous allons l’illustrer.</li>
</ul>
<p>Mettons que nous ayons pour besoin que la vue index nous redirige vers l’action datetime. Il suffit de l’implémenter de cette manière :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function indexAction() <br />
{ <br />
&nbsp; $this-&gt;_forward('datetime'); <br />
}</div></div>
<p>Si on appelle notre application via http://myapp/index/datetime, aucun soucis. Si on appelle notre application via http://myapp/, c’est le drame, une exception est levée :<br />
<blockquote>Message: Cannot add context &laquo;&nbsp;txt&nbsp;&raquo;; already exists</p></blockquote>
<p>La raison est simple : en utilisant forward, la boucle de dispatch instancie à nouveau le contrôleur et déclenche un second appel de la méthode init. Le contexte est donc créé deux fois ce qui provoque une exception.</p>
<p>Si notre contexte était si unique, nous aurions pu créer le contexte directement dans la méthode datetime me direz-vous ? Et vous auriez raison, le peu de temps avant que la direction ne vous demande une méthode date et une méthode time qui utilise le même contexte&#8230;</p>
<p>Nous allons résoudre le problème autrement, et définir le contexte une bonne fois pour toute, accessible dans toute notre application. De cette manière, il sera réutilisable ailleurs, et même exploitable en dehors de ce projet si nécessaire.</p>
<p>La première chose à faire est de retirer l’ajout de contexte de la méthode init :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function init() <br />
{ <br />
&nbsp; $this-&gt;_helper <br />
&nbsp; &nbsp; &nbsp;-&gt;contextSwitch <br />
&nbsp; &nbsp; &nbsp;-&gt;addActionContext('datetime', 'txt') <br />
&nbsp; &nbsp; &nbsp;-&gt;initContext(); <br />
}</div></div>
<p>Ensuite, il faut configurer notre ActionHelper en amont. Après m’être penché un peu sur le sujet, je pense que le plus simple et efficace consiste à utiliser le Bootstrap, par exemple en ajoutant une méthode _initContextSwitch :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Bootstrap extends Zend_Application_Bootstrap_Bootstrap <br />
{ <br />
&nbsp; protected function _initContextSwitch() <br />
&nbsp; { <br />
&nbsp; &nbsp; $contextSwitch = new Zend_Controller_Action_Helper_ContextSwitch(); <br />
&nbsp;<br />
&nbsp; &nbsp; $contextSwitch-&gt;addContext('txt', array ('suffix' =&gt; 'txt', <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'headers' =&gt; array('content-type' =&gt; 'text/plain'))); <br />
&nbsp;<br />
&nbsp; &nbsp; Zend_Controller_Action_HelperBroker::addHelper($contextSwitch); <br />
&nbsp; } <br />
}</div></div>
<p>Vous êtes libres de configurer à votre guise l’ActionHelper soit directement dans la méthode du Bootstrap, soit un utilisant des paramètres passés dans le fichier de configuration, créer une ressource pour Zend_Application&#8230;</p>
<p>La seule chose que je ne recommanderais pas serait de créer une classe héritant de Zend_Application_ContextSwitch : si vous voulez vous faire votre avis, allez jeter un oeil sur le constructeur et la méthode init de cet ActionHelper : il est assez délicat de modifier son comportement sans casser son fonctionnement exact, du moins sans réécriture massive du code.</p>
<p>Je suis bien entendu ouvert à tout avis, critiques, questions et retours d’expérience à ce sujet !</p>
<p><em>Le code a été écrit et testé avec le Zend Framework dans sa version 1.10.5.</em></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend_Form et vérification client-side des données</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p8990/php/zend-framework/zend_form_verification_client_side</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p8990/php/zend-framework/zend_form_verification_client_side#comments</comments>
		<pubDate>Sat, 12 Jun 2010 10:36:29 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[Mootools]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[En regardant ce screencast je me suis rappelé de précédents essais de formulaire à validation &#171;&#160;automatique&#160;&#187; côté client. L&#8217;idée était, sur le papier, très sexy : Conception d&#8217;une classe Javascript de vérification réellement réutilisable, sans retoucher le code pour chaque formulaire. Uniformisation du contrôle client et serveur : si les spécifications du formulaire change, il suffit de modifier notre Zend_Form et tout le reste suis. Seulement voilà, le projet était à petit budget, et si [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>En regardant <a href="http://www.zendcasts.com/ajaxify-your-zend_form-validation-with-jquery/2010/04/" target="_blank">ce screencast</a> je me suis rappelé de précédents essais de formulaire à validation &laquo;&nbsp;automatique&nbsp;&raquo; côté client.</p>
<p>L&rsquo;idée était, sur le papier, très sexy : </p>
<ul>
<li>Conception d&rsquo;une classe Javascript de vérification réellement réutilisable, sans retoucher le code pour chaque formulaire.</li>
<li>Uniformisation du contrôle client et serveur : si les spécifications du formulaire change, il suffit de modifier notre Zend_Form et tout le reste suis.</li>
</ul>
<p><span id="more-7"></span><br />
Seulement voilà, le projet était à petit budget, et si le volume d&rsquo;utilisateur était faiblard, le mutualisé l&rsquo;hébergeant l&rsquo;était plus encore : s&rsquo;ensuivait des freeze à chaque validation de formulaire, qui m&rsquo;a complètement freiné dans l&rsquo;utilisation sur le onblur des éléments au lieu du submit du form, ce qui faisait perdre une grosse partie de la réactivité (la validation client-side attendait sagement qu&rsquo;on valide le formulaire pour se faire, ce qui était d&rsquo;un intérêt discutable&#8230;).</p>
<p>Conclusion : c&rsquo;était un bonheur à programmer, et une horreur à utiliser.</p>
<p>Depuis les besoins ont fait que je me suis &laquo;&nbsp;contenté&nbsp;&raquo; de formulaire à l&rsquo;ancienne, avec une validation server-side only. Ayant eut beaucoup d&rsquo;application métier à développer ça n&rsquo;a pas choqué grand monde : les utilisateurs étaient contents, c&rsquo;était carré, ça fonctionnait, c&rsquo;était fluide. Mais il faut l&rsquo;avouer, ça n&rsquo;était pas très sexy.</p>
<p>Ce screencast a fait germer l&rsquo;idée de refaire un essai, plus ambitieux, plus carré, mais tout aussi évolutif et maintenable.</p>
<p>Mon objectif ? Trouver une façon simple mais robuste de lier les Zend_Form au <a href="http://mootools.net/docs/more/Forms/Form.Validator" target="_blank">Form.Validator</a> de Mootools, de façon à offrir un contrôle homogène entre server-side et client-side, sans appel Ajax superflu : on réservera les appels Ajax aux besoins dont le serveur est indispensable, notamment vérifier l&rsquo;unicité d&rsquo;une valeur dans une table.</p>
<p>Je réfléchis à un plan d&rsquo;attaque, et on se tient au courant <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ContextSwitch : cohabitation avec AjaxContext</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p8744/php/contextswitch_cohabitation_ajaxcontext</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p8744/php/contextswitch_cohabitation_ajaxcontext#comments</comments>
		<pubDate>Sun, 21 Mar 2010 10:58:44 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[L&#8217;aide de contrôleur qu&#8217;est ContextSwitch est une réelle force pour vos applications : simplement et de manière très élégante, vous pouvez réutilisez vos vues pour servir les même données selon des formats différents. Sur le même principe, AjaxContext vous permet d&#8217;implémenter des fonctionnalités Ajax sans remettre en cause la structure de votre application. Cependant, le développeur qui voudra faire cohabiter ContextSwitch et AjaxContext au sein d&#8217;une même vue se heurtera à un problème que l&#8217;on [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>L&rsquo;aide de contrôleur qu&rsquo;est ContextSwitch est une réelle force pour vos applications : simplement et de manière très élégante, vous pouvez réutilisez vos vues pour servir les même données selon des formats différents. Sur le même principe, AjaxContext vous permet d&rsquo;implémenter des fonctionnalités Ajax sans remettre en cause la structure de votre application. Cependant, le développeur qui voudra faire cohabiter ContextSwitch et AjaxContext au sein d&rsquo;une même vue se heurtera à un problème que l&rsquo;on abordera ici.<br />
<span id="more-6"></span><br />
Cette (courte) série d&rsquo;articles aura pour but de pointer du doigt quelques problématiques concrètes d&rsquo;utilisation des helpers ContextSwitch et AjaxContext. Pour plus d&rsquo;informations sur leur fonctionnement, je vous laisse le soin de consulter la documentation : http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch</p>
<p>Prenons un exemple simple. Nous allons afficher quelques données en HTML, et nous voulons avoir un export XML des même données. Dans le cadre d&rsquo;une utilisation au sein d&rsquo;un formulaire dynamique, nous génèrerons ces données sous forme d&rsquo;une liste select dans l&rsquo;éventualité d&rsquo;un appel Ajax.</p>
<p>Voici le code de notre controller :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public function init () <br />
{ <br />
&nbsp; $this-&gt;_helper-&gt;contextSwitch <br />
&nbsp; &nbsp; -&gt;addActionContext('index', 'xml') <br />
&nbsp; &nbsp; -&gt;initContext(); <br />
&nbsp;<br />
&nbsp; $this-&gt;_helper-&gt;AjaxContext <br />
&nbsp; &nbsp; -&gt;addActionContext('index', 'html') <br />
&nbsp; &nbsp; -&gt;initContext(); <br />
} <br />
&nbsp;<br />
public function indexAction () <br />
{ <br />
&nbsp; $this-&gt;view-&gt;data = array( <br />
&nbsp; &nbsp; 'value1' =&gt; 'text1', <br />
&nbsp; &nbsp; 'value2' =&gt; 'text2', <br />
&nbsp; &nbsp; 'value3' =&gt; 'text3', <br />
&nbsp; &nbsp; 'value4' =&gt; 'text4', <br />
&nbsp; ); <br />
}</div></div>
<p>Et voici nos vues :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// index.phtml <br />
&lt;?php foreach ($this-&gt;data as $value =&gt; $text) : ?&gt; <br />
&lt;div id=&quot;&lt;?php echo $this-&gt;escape($value); ?&gt;&quot;&gt; <br />
&lt;?php echo $this-&gt;escape($text); ?&gt; <br />
&lt;/div&gt; <br />
&lt;?php endforeach; ?&gt; <br />
&nbsp;<br />
// index.xml.phtml <br />
&lt;?php echo '&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;'; ?&gt; <br />
&lt;root&gt; <br />
&nbsp; &lt;?php foreach ($this-&gt;data as $value =&gt; $text) : ?&gt; <br />
&nbsp; &lt;row&gt; <br />
&nbsp; &nbsp; &lt;value&gt;&lt;?php echo $this-&gt;escape($value); ?&gt;&lt;/value&gt; <br />
&nbsp; &nbsp; &lt;text&gt;&lt;?php echo $this-&gt;escape($text); ?&gt;&lt;/text&gt; <br />
&nbsp; &lt;/row&gt; <br />
&nbsp; &lt;?php endforeach; ?&gt; <br />
&lt;/root&gt; <br />
&nbsp;<br />
// index.ajax.phtml <br />
&lt;?php echo $this-&gt;formSelect('data', null, null, $this-&gt;data); ?&gt;</div></div>
<p>Et voici le retour que l&rsquo;on aurait pour chacune de ces vues :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// Appel classique <br />
&lt;div id=&quot;value1&quot;&gt;text1&lt;/div&gt; <br />
&lt;div id=&quot;value2&quot;&gt;text2&lt;/div&gt; <br />
&lt;div id=&quot;value3&quot;&gt;text3&lt;/div&gt; <br />
&lt;div id=&quot;value4&quot;&gt;text4&lt;/div&gt; <br />
&nbsp;<br />
// format == xml <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt; <br />
&lt;root&gt; <br />
&nbsp; &lt;row&gt; <br />
&nbsp; &nbsp; &lt;value&gt;value1&lt;/value&gt; <br />
&nbsp; &nbsp; &lt;text&gt;text1&lt;/text&gt; <br />
&nbsp; &lt;/row&gt; <br />
&nbsp; &lt;row&gt; <br />
&nbsp; &nbsp; &lt;value&gt;value2&lt;/value&gt; <br />
&nbsp; &nbsp; &lt;text&gt;text2&lt;/text&gt; <br />
&nbsp; &lt;/row&gt; <br />
&nbsp; &lt;row&gt; <br />
&nbsp; &nbsp; &lt;value&gt;value3&lt;/value&gt; <br />
&nbsp; &nbsp; &lt;text&gt;text3&lt;/text&gt; <br />
&nbsp; &lt;/row&gt; <br />
&nbsp; &lt;row&gt; <br />
&nbsp; &nbsp; &lt;value&gt;value4&lt;/value&gt; <br />
&nbsp; &nbsp; &lt;text&gt;text4&lt;/text&gt; <br />
&nbsp; &lt;/row&gt; <br />
&lt;/root&gt; <br />
&nbsp;<br />
// Appel Ajax, format == html <br />
Exception information: <br />
Message: Context &quot;html&quot; does not exist</div></div>
<p>Inutile de préciser que ce n&rsquo;était pas trop le résultat attendu&#8230; Essayons maintenant de comprendre pourquoi. Si il vient assez rapidement de sentir un problème de conflit entre ContextSwitch et AjaxContext, quelques séances de debugging permettent de mettre le doigt sur le coeur du problème.</p>
<p>La première chose, est qu&rsquo;en désactivant ContextSwitch notre contexte Ajax fonctionne parfaitement, cela nous conforte donc dans la théorie du conflit entre les deux helpers. Ensuite en regardant le cheminement de notre application lors d&rsquo;une séance de debug, l&rsquo;on se rends compte que l&rsquo;helper ContextSwitch se déclenche en premier à la détection du paramètre format. Par conséquent, il lève une exception car il ne connaît pas le format html.</p>
<p>A ma connaissance, il n&rsquo;existe pas de manière de modifier ce comportement, et même si il m&rsquo;aurait paru plus logique qu&rsquo;en présence d&rsquo;une requête Ajax l&rsquo;helper AjaxContext prenne le dessus sur le ContextSwitch, je me plais à croire qu&rsquo;il y a une raison valable à tout ça. A ce sujet, si quelqu&rsquo;un  bout dispose d&rsquo;un élément de réponse, je suis preneur <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
<p>La solution la plus simple que j&rsquo;ai trouvé pour ce problème est la suivante : modifier le paramètre devant définir le format, ce qui se fait simplement avec la méthode setContextParam(). Voici comment nous initialisons notre AjaxContext maintenant :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$this-&gt;_helper-&gt;AjaxContext <br />
&nbsp; -&gt;addActionContext('index', 'html') <br />
&nbsp; -&gt;setContextParam('ajax') <br />
&nbsp; -&gt;initContext();</div></div>
<p>Désormais, plus de conflit, il suffit de spécifier /Ajax/html dans l&rsquo;url de notre requête Ajax et tout marchera correctement. En espérant que ça dépanne quelqu&rsquo;un qui un jour se serait retrouvé confronté au problème <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>De la théorie à la pratique : s&#8217;approprier le Zend Framework</title>
		<link>https://blog.developpez.com/lucas-corbeaux/p8694/php/de_la_theorie_a_la_pratique_s_approprier</link>
		<comments>https://blog.developpez.com/lucas-corbeaux/p8694/php/de_la_theorie_a_la_pratique_s_approprier#comments</comments>
		<pubDate>Sat, 06 Mar 2010 09:39:07 +0000</pubDate>
		<dc:creator><![CDATA[Nighty]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Se retrouver face au Zend Framework pour la première fois impressionne. On a beau avoir lu toute la documentation possible, acquiescé d&#8217;un signe de tête convaincu à chaque fin de paragraphe pour marquer l&#8217;appropriation de chaque concept, il se trouve que le jour J, on se retrouve comme un gallinacé face à un ustensile de cuisine : on a beau avoir l&#8217;intime conviction que ça va nous être indispensable, on se demande par quel bout [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Se retrouver face au Zend Framework pour la première fois impressionne. On a beau avoir lu toute la documentation possible, acquiescé d&rsquo;un signe de tête convaincu à chaque fin de paragraphe pour marquer l&rsquo;appropriation de chaque concept, il se trouve que le jour J, on se retrouve comme un gallinacé face à un ustensile de cuisine : on a beau avoir l&rsquo;intime conviction que ça va nous être indispensable, on se demande par quel bout le prendre.<br />
<span id="more-5"></span><br />
Quiconque aura tenté l&rsquo;expérience de but en blanc l&rsquo;aura constaté : développer un projet de A à Z basé sur le Zend Framework revient à répéter inlassablement les même portions de code. S&rsquo;approprier le Zend Framework passe à mon avis par la conception de sa propre bibliothèque (même light) afin de factoriser les éléments couramment utilisés.</p>
<p>Cet article n&rsquo;a pas but de vous convaincre de quoi que ce soit, je vous expose juste une « façon de faire » qui jusqu&rsquo;ici m&rsquo;a plutôt bien réussi sur des projets de taille modérée. Il parle de concepts propres à Zend Framework 1.8 et ultérieurs : namespaces, application, ressources&#8230;<br />
Si vous n&rsquo;êtes pas familier avec ceci, je vous conseille de jeter un oeil ici : http://framework.zend.com/manual/en/zend.application.html<br />
Et pour les namespaces de l&rsquo;autoloader, c&rsquo;est ici : http://framework.zend.com/manual/en/zend.loader.autoloader.html</p>
<p>La première chose consiste à créer ses bibliothèques personnelles, qui serviront pour le projet courant, et  pour les projets à venir. J&rsquo;utilise systématiquement deux namespaces pour chaque projet : le namespace de l&rsquo;entreprise, et celui du projet en question. Cela permet de cloisonner les problématiques communes des besoins réellement spécifiques. Dans les exemples qui suivent, on considérera que le namespace d&rsquo;entreprise est MyCompany et le namespace du projet MyProject. </p>
<p>Personnellement je dérive systématiquement les classes Zend_Db_Table (ainsi que les Row et Rowset) et la classe Zend_Controller_Action, même quand je n&rsquo;ai rien à y mettre pour le moment. De cette manière, si jamais un traitement générique devait être décidé plus tard (par exemple passer à la vue un id Google Analytics) il serait encore possible de manoeuvrer sans remettre en cause tout notre projet. De la même manière, si on veut implémenter un algorithme maison de vérification des données avant toute sauvegarde, on sera bien content que toutes nos tables soient des classes filles de notre dérivée de Zend_Db_Table.</p>
<p>Prenons par exemple l&rsquo;IndexController, sa classe mère sera MyProject_Controller_Action, elle même fille de MyCompany_Controller_Action, fille de Zend_Controller_Action. Un peu lourd à mettre en place en début de projet, ça devient bénin par la suite et permet une grande souplesse&#8230; On pourrait même aller plus loin, et créer un contrôleur type par module du projet si le besoin se faisait sentir.</p>
<p>Le reste de la bibliothèque sera beaucoup plus dépendant de vos besoins réels, mais quelques outils tels qu&rsquo;un loader de formulaire ou de modèle pourrait grandement aider dans une majorité des cas&#8230; Une règle d&rsquo;or toutefois : le but est bien de factoriser le maximum de code que l&rsquo;on peut, mais il ne faut pas tomber dans l&rsquo;excès. Certains cas par exemple semblent très facilement factorisable, mais leur évolution est quasiment impossible à prédire. Ca peut être le cas de la sauvegarde des données depuis un formulaire, ou toute demande ultérieure peut venir casser et / ou largement complexifier votre algorithme initial (qu&rsquo;arrivera-t-il si on modifie l&rsquo;interface pour diviser le formulaire en plusieurs pages, ou si on ajoute de nombreux éléments qui n&rsquo;ont pas à être enregistrés mais qui influent sur le traitement&#8230;).</p>
<p>Enfin, pensez réutilisation : vous avez besoin d&rsquo;une ressource supplémentaire dans votre bootstrap ? Même si celle-ci est propre au projet, tant que c&rsquo;est possible privilégiez la création d&rsquo;une classe de ressource plutôt que d&rsquo;un élément de code « en dur » dans la classe de bootstrap. Comme ça, si le besoin s&rsquo;avère plus général que prévu de prime abord, il sera toujours temps de la faire passer de MyProject vers MyCompany pour le prochain projet&#8230;</p>
<p>Un dernier conseil : le Zend Framework évolue vite. Aussi, si il est de bon ton de dériver les classes du Zend Framework pour leur greffer des traitements plus « personnels », faites attention à ne pas tout remettre en cause, ou vous risqueriez de passer pas mal de temps d&rsquo;adaptation à la prochaine mise à jour majeure du Framework&#8230; Dans le même esprit, quand vous implémentez une ressource, un service, une conversion de mesure qui vous paraît très commune et qui pourtant est absente du Framework, n&rsquo;en faites pas plus que le nécessaire. Il y a fort à parier qu&rsquo;une version officielle sortira tôt ou tard, aussi contentez-vous du besoin du moment, il sera toujours temps d&rsquo;utiliser la solution officielle quand elle existera. Prenons le cas de la ressource Log, sortis avec Zend Framework 1.10, et dont j&rsquo;ai dû créer un ersatz cet été pour les besoins de deux projets : y passer plus longtemps pour prendre en compte plus de cas de figures aurait été inutile, vu que le manque est désormais comblé.</p>
<p>J&rsquo;espère que ce bref article aidera quelques lecteurs à se représenter leurs futurs projets Zend Framework, ou au moins qu&rsquo;il soulèvera quelques commentaires <img src="https://blog.developpez.com/lucas-corbeaux/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
<p><em>N. B. : Après mûre réflexion, je ne suis pas totalement persuadé de l&rsquo;indispensabilité du couteau pour la poule.</em></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
