<?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>Symfonic</title>
	<atom:link href="http://www.symfonic.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.symfonic.fr</link>
	<description>Parlons de trucs sur Symfony !</description>
	<lastBuildDate>Mon, 18 Apr 2011 15:13:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Un post validator pour gérer les dépendances entre les champs</title>
		<link>http://www.symfonic.fr/2011/04/un-post-validator-pour-gerer-les-dependances-entre-les-champs/</link>
		<comments>http://www.symfonic.fr/2011/04/un-post-validator-pour-gerer-les-dependances-entre-les-champs/#comments</comments>
		<pubDate>Mon, 18 Apr 2011 15:05:23 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[dépendance]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[validator]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=190</guid>
		<description><![CDATA[Aujourd'hui, je partage un post validator qui permet de définir des dépendances entre des champs. Il permet par exemple de définir que le champ postal_code n'est requis que si le champ country vaut FR. Voici donc cette classe : &#60;?php /** * sfValidatorSchemaDependency allows to define dependency between fields */ class sfValidatorSchemaDependency extends sfValidatorSchema { [...]]]></description>
			<content:encoded><![CDATA[<p>Aujourd'hui, je partage un post validator qui permet de définir des dépendances entre des champs. Il permet par exemple de définir que le champ <em>postal_code</em> n'est requis que si le champ <em>country</em> vaut <em>FR</em>.</p>
<p>Voici donc cette classe :</p>
<pre class="brush: php; title: ;">
&lt;?php

/**
 * sfValidatorSchemaDependency allows to define dependency between fields
 */
class sfValidatorSchemaDependency extends sfValidatorSchema
{

  /**
   * Constructor.
   *
   * Available options:
   *
   *  * affected_field:  The field that is required or not
   *  * expected_values: A key/value array that represents the fields and their value
   *                     that must be matched to set the affected_field as required
   *
   * @param string $affected_field   The field that is required or not
   * @param array  $expected_values  A key/value array that represents the fields and their value
   *                                 that must be matched to set the affected_field as required
   * @param array  $options          An array of options
   * @param array  $messages         An array of error messages
   *
   * @see sfValidatorBase
   */
  public function __construct($affected_field, $expected_values, $options = array(), $messages = array())
  {
    $this-&gt;addOption('affected_field', $affected_field);
    $this-&gt;addOption('expected_values', $expected_values);

    parent::__construct(null, $options, $messages);
  }

  /**
   * @see sfValidatorBase
   */
  protected function doClean($values)
  {
    if (null === $values)
    {
      $values = array();
    }

    if (!is_array($values))
    {
      throw new InvalidArgumentException('You must pass an array parameter to the clean() method');
    }

    $affected_field = isset($values[$this-&gt;getOption('affected_field')]) ? $values[$this-&gt;getOption('affected_field')] : null;

    $bAllValuesMatched = true;
    foreach ($this-&gt;getOption('expected_values') as $field =&gt; $value)
    {
      // if a field has not the expected value
      if (!isset($values[$field]) || $values[$field] != $value)
      {
        $bAllValuesMatched = false;
        break;
      }
    }

    // if every field has the expected value, and affected_field not defined
    if ($bAllValuesMatched &amp;&amp; !$affected_field)
    {
      // &quot;affected_field is required&quot; error
      throw new sfValidatorErrorSchema($this, array(
        $this-&gt;getOption('affected_field') =&gt; new sfValidatorError($this, 'required')
      ));
    }

    return $values;
  }
}
</pre>
<p>Et voici comment l'utiliser dans le cas de l'exemple de notre introduction :</p>
<pre class="brush: php; title: ;">
  /**
   * @see sfForm::configure()
   */
  public function configure()
  {
    // ...
    $this-&gt;mergePostValidator(new sfValidatorSchemaDependency('postal_code', array('country' =&gt; 'FR')));
  }
</pre>
<p>Ainsi, lors de la validation du formulaire, si le champ <em>country</em> vaut <em>FR</em> et si le champ <em>postal_code</em> est vide, une <em>sfValidatorError</em> de type <em>required</em> va être liée au champ <em>postal_code</em>.</p>
<p>Notez qu'il est possible de définir plusieurs dépendances, en passant plusieurs éléments dans le tableau en second paramètre du constructeur de <em>sfValidatorSchemaDependency</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2011/04/un-post-validator-pour-gerer-les-dependances-entre-les-champs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Créer un panel pour la Web Debug Toolbar utilisant l&#8217;Event Dispatcher</title>
		<link>http://www.symfonic.fr/2011/02/web-debug-toolbar-event-dispatcher/</link>
		<comments>http://www.symfonic.fr/2011/02/web-debug-toolbar-event-dispatcher/#comments</comments>
		<pubDate>Wed, 09 Feb 2011 09:48:18 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[dispatcher]]></category>
		<category><![CDATA[événement]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[panel]]></category>
		<category><![CDATA[toolbar]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=150</guid>
		<description><![CDATA[Allez, un petit tutoriel aujourd'hui. On va créer un panel pour la WDT (Web Debug Toolbar) qui va afficher la liste des requêtes WebService SOAP (mais vous pouvez l'adapter à ce que vous voulez) exécutées sur la page, à la manière des panels Doctrine/Propel (dont je me suis inspirés) qui affichent les requêtes SQL. Son [...]]]></description>
			<content:encoded><![CDATA[<p>Allez, un petit tutoriel aujourd'hui. On va créer un panel pour la WDT (Web Debug Toolbar) qui va afficher la liste des requêtes WebService SOAP (mais vous pouvez l'adapter à ce que vous voulez) exécutées sur la page, à la manière des panels Doctrine/Propel (dont je me suis inspirés) qui affichent les requêtes SQL. Son contenu sera alimenté par des événements gérés par l'Event Dispatcher.</p>
<p>Pour la création du squelette du panel <em>sfWebDebugPanelSoapClient</em>, je vous laisse suivre le <a href="http://www.symfony-project.org/more-with-symfony/1_4/fr/07-Extending-the-Web-Debug-Toolbar" target="_blank">tutoriel officiel</a>, qui est très bien fait. Une fois que c'est fait, on va remplir ce panel en utilisant l'Event Dispatcher. Pour cela, on va commencer par générer les événements ; ça se passe donc dans mon cas dans la class <em>MySoapClient</em>, la classe qui gère les choses que je veux logger.</p>
<p>Je commence par y créer la méthode qui crée et dispatche l'événement :</p>
<pre class="brush: php; title: ;">
  /**
   * Dispatch a 'soapclient.log' event (used by web debug panel)
   *
   * @param SoapCommand $oCommand  The executed command
   * @param int         $iDuration The duration of the soap call
   */
  protected function dispatchEvent($oCommand, $iDuration)
  {
    $this-&gt;context-&gt;getEventDispatcher()-&gt;notify(new sfEvent($this, 'soapclient.log', array(
      'command'  =&gt; $oCommand,
      'duration' =&gt; $iDuration,
    )));
  }
</pre>
<p>Comme vous le voyez, je crée un événement de type "soapclient.log" portant sur l'objet courant (<em>$this</em>), et je fournis au passage des paramètres informatifs que j'afficherai dans mon panel un peu plus tard... Puis j'utilise l'Event Dispatcher pour notifier les objets qui écoutent les événements "soapclient.log" qu'il y en a un nouveau !</p>
<p>Il faut ensuite appeler cette méthode au moment opportun, dans mon cas, immédiatement après l'appel au WebService.</p>
<pre class="brush: php; title: ;">
    $iTime = microtime(true);
    // do your stuff...
    $this-&gt;dispatchEvent($oCommand, microtime(true) - $iTime);
</pre>
<p>Retournons maintenant dans la classe panel <em>sfWebDebugPanelSoapClient</em>, afin justement de lui dire d'écouter ce type d'événements. Pour cela, on va surcharger son constructeur afin de connecter une méthode à cet événement.</p>
<pre class="brush: php; title: ;">
  protected $aEvents = array();

  public function __construct(sfWebDebug $webDebug)
  {
    parent::__construct($webDebug);
    $this-&gt;webDebug-&gt;getEventDispatcher()-&gt;connect('soapclient.log', array($this, 'listenForSoapClientLogs'));
  }

  /**
   * Listens to soapclient.log event and record them
   *
   * @param sfEvent $event
   */
  public function listenForSoapClientLogs(sfEvent $event)
  {
    $this-&gt;aEvents[] = $event;
  }
</pre>
<p>Dans le constructeur, on demande à l'Event Dispatcher d'appeler la méthode "listenForSoapClientLogs" de notre classe dès qu'il reçoit un événement de type "soapclient.log". Dans cette méthode, on stocke juste chaque événement reçu dans un tableau, propriété de notre classe.</p>
<p>On a désormais toutes les billes. Il n'y a plus qu'à afficher le tout dans notre panel.</p>
<pre class="brush: php; title: ;">
  /**
   * Get the html content of the panel
   *
   * @return string $html
   */
  public function getPanelContent()
  {
    return '
    &lt;div id=&quot;sfWebDebugSoapClientLogs&quot;&gt;
      &lt;ol&gt;'.implode(&quot;\n&quot;, $this-&gt;getSoapClientLogs()).'&lt;/ol&gt;
    &lt;/div&gt;
    ';
  }

  /**
   * Retrieves events as html
   *
   * @return string
   */
  protected function getSoapClientLogs()
  {
    $aRet = array();
    $i = 1;
    foreach ($this-&gt;aEvents as $oEvent)
    {
      $aParams = $oEvent-&gt;getParameters();

      $oClient = $oEvent-&gt;getSubject();
      $oCommand = $aParams['command'];

      $sHtml = '
        &lt;li&gt;
          ' . get_class($oCommand) . ' (' . round(($aParams['duration'] * 1000), 2) . ' ms)
          ...
        &lt;/li&gt;
      ';

      $aRet[] = $sHtml;
      $i++;
    }
    return $aRet;
  }
</pre>
<p>Et voilà ! Le tour est joué ! On a un joli panel pour débugger dans mon cas un client SOAP, mais je suis sûr que vous en ferez plein de trucs utiles !</p>
<p><a href="http://www.symfonic.fr/wp-content/uploads/2011/02/soapdebug.png"><img src="http://www.symfonic.fr/wp-content/uploads/2011/02/soapdebug-300x75.png" alt="Soap Debug Panel" title="Soap Debug Panel" width="300" height="75" class="aligncenter size-medium wp-image-168" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2011/02/web-debug-toolbar-event-dispatcher/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ValidatorEmailList : valider une liste d&#8217;e-mails</title>
		<link>http://www.symfonic.fr/2011/01/validatoremaillist-valider-une-liste-de-mails/</link>
		<comments>http://www.symfonic.fr/2011/01/validatoremaillist-valider-une-liste-de-mails/#comments</comments>
		<pubDate>Tue, 25 Jan 2011 08:35:35 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[validator]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=121</guid>
		<description><![CDATA[Voici un petit validateur pas très compliqué mais pratique, qui valide une liste d'adresses e-mails présentes dans un champ type "textarea". class ValidatorEmailList extends sfValidatorBase &#123; &#160; public function doClean&#40;$value&#41; &#160; &#123; &#160; &#160; $aValues = explode&#40;&#34;\n&#34;, $value&#41;; &#160; &#160; $aValues = array_map&#40;&#39;trim&#39;, $aValues&#41;; &#160; &#160; $aEmails = array&#40;&#41;; &#160; &#160; &#160; &#160; $oEmailValidator = [...]]]></description>
			<content:encoded><![CDATA[<p>Voici un petit validateur pas très compliqué mais pratique, qui valide une liste d'adresses e-mails présentes dans un champ type "textarea".</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">class</span> ValidatorEmailList <span class="kw2">extends</span> sfValidatorBase</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> doClean<span class="br0">&#40;</span><span class="re1">$value</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re1">$aValues</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="sy0">,</span> <span class="re1">$value</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re1">$aValues</span> <span class="sy0">=</span> <span class="kw3">array_map</span><span class="br0">&#40;</span><span class="st0">&#39;trim&#39;</span><span class="sy0">,</span> <span class="re1">$aValues</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re1">$aEmails</span> <span class="sy0">=</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re1">$oEmailValidator</span> <span class="sy0">=</span> <span class="kw2">new</span> sfValidatorEmail<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re1">$aValues</span> <span class="kw1">as</span> <span class="re1">$sEmail</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="co1">// ignore empty lines</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re1">$sEmail</span> <span class="sy0">!=</span> <span class="st0">&#39;&#39;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// verify email syntax using sfValidatorEmail</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// sfValidatorError exception will be thrown if invalid</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$oEmailValidator</span><span class="sy0">-&gt;</span><span class="me1">clean</span><span class="br0">&#40;</span><span class="re1">$sEmail</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$aEmails</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="re1">$sEmail</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re1">$aEmails</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Ça me fait penser qu'on pourrait améliorer ça en passant le validateur (ici "new sfValidatorEmail()") en option de ValidatorEmailList pour pouvoir valider des listes de ce qu'on veut en fait... Enfin je vous laisse le faire !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2011/01/validatoremaillist-valider-une-liste-de-mails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Projet sfAntiBruteForcePlugin</title>
		<link>http://www.symfonic.fr/2010/12/projet-sfantibruteforceplugin/</link>
		<comments>http://www.symfonic.fr/2010/12/projet-sfantibruteforceplugin/#comments</comments>
		<pubDate>Sat, 11 Dec 2010 11:32:58 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Brute force]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[Sécurité]]></category>
		<category><![CDATA[sfAntiBruteForcePlugin]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=118</guid>
		<description><![CDATA[Récemment j'ai créé une petite application web pour jouer un peu avec les API de twitter, qui est sécurisée par un classique login / mot de passe : sécurité basique. Je me suis rapidement dit qu'il faudrait ajouter une sécurité pour parer aux attaques de type "brute force". Pour rappel, ce type d'attaque consiste à [...]]]></description>
			<content:encoded><![CDATA[<p>Récemment j'ai créé une petite application web pour jouer un peu avec les <a title="API Twitter" href="http://dev.twitter.com/">API de twitter</a>, qui est sécurisée par un classique login / mot de passe : sécurité basique. Je me suis rapidement dit qu'il faudrait ajouter une sécurité pour parer aux attaques de type "brute force". Pour rappel, ce type d'attaque consiste à tenter un maximum de couples login / mot de passe sur un formulaire en espérant trouver des identifiants qui fonctionnent (<a title="brute force sur wikipedia" href="http://fr.wikipedia.org/wiki/Attaque_par_force_brute">plus d'info</a>). J'ai rapidement cherché quelques informations à ce sujet et espéré trouvé un plugin symfony tout fait (on peut espérer non ?). Résultat : pas de plugin, mais quelques informations intéressantes qui m'ont donné envie de me lancer dans le développement du fameux plugin que je cherchais ! Je vais donc recenser ces informations ici, faire une sorte de cahier des charges collaboratif pour mon plugin, et j'espère bien que vous allez m'y aider !</p>
<p>La plupart des informations intéressantes que j'ai récoltées proviennent de ce tutoriel : <a title="Le site du zero" href="http://www.siteduzero.com/tutoriel-3-61380-un-anti-brute-force-leger-et-rapide.html">un anti brute-force léger et rapide</a>.</p>
<p><strong>Le principe</strong> : empêcher un utilisateur et surtout un robot de tenter une infinité de couples login / mot de passe sur une page d'authentification donnée. Pour cela, on doit compter les tentatives erronées des utilisateurs, et les empêcher à partir d'un certain seuil de tentatives par unité de temps. Voici les questions qui en découlent.</p>
<p><strong>Sur quoi se baser pour compter les tentatives ?</strong></p>
<p>Sur l'IP du client ? Mauvaise idée, cette donnée n'est pas fiable, la plupart des hackers sauront la modifier et pourront donc faire une infinité de tentatives.</p>
<p>Sur les sessions ? Non plus, il suffit d'effacer le cookie et c'est reparti pour d'autres tentatives...</p>
<p>Sur le login utilisé pour l'authentification ? Ce n'est pas une solution parfaite, mais c'est la meilleure que j'ai trouvé à ce jour. L'inconvénient principal est que n'importe qui peut bloquer le compte de quelqu'un s'il connait son login...</p>
<p>Si vous avez d'autres idées, je suis preneur !</p>
<p><strong>Comment stocker le nombre de tentatives effectuées ?</strong></p>
<p>En base de données ? Ca semble être la solution la plus logique. Néanmoins, certains projets ne fonctionnent pas avec une base de données (et c'est mon cas ici !). Ce serait un peu intrusif de devoir créer une base pour ça, de charger un ORM etc.</p>
<p>Dans des fichiers ? C'est la solution qu'a choisi l'article ci-dessus. Niveau rapidité, charge etc., il faudrait faire un comparatif avec l'utilisation d'un ORM  pour savoir qui est le meilleur. Cette solution est moins envahissante dans la mesure où elle fonctionnerait sur tous les projets symfony (à ma connaissance).</p>
<p>Si vous avez d'autres idées...</p>
<p><strong>Où intervenir au niveau du code symfony ?</strong></p>
<p>A la base, j'avais pensé qu'il faudrait faire un filtre pour contrôler les accès en amont dans l'application. Le problème est que, si je pars sur la solution d'utiliser le login pour compter les tentatives, j'ai besoin de ce login pour incrémenter son compteur de tentatives en cas d'échec. J'ai donc également besoin de savoir si la tentative d'autentification est un échec ou non. Pour cela, j'ai donc besoin d'internvenir au niveau du contrôleur, dans l'action qui gère l'authentification. J'imagine que le développeur devra ajouter un appel de ce genre lorsqu'une tentative d'authentification échouera :</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1">sfAntiBruteForceManager<span class="sy0">::</span><span class="me2">notifyFailedAuthentication</span><span class="br0">&#40;</span><span class="re1">$identifier</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
</ol>
</div>
<p>Cette méthode aura pour but d'incrémenter le compteur d'échec pour cet utilisateur.</p>
<p>Il faudrait également, avant la tentative d'authentification, vérifier que l'utilisateur qui s'apprête à s'authentifier a le droit de le faire :</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span>sfAntiBruteForceManager<span class="sy0">::</span><span class="me2">canTryAuthentication</span><span class="br0">&#40;</span><span class="re1">$identifier</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="co1">// ...</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p><strong>Faut-il s'intégrer au plugin sfGuard ?</strong></p>
<p>Dans un second temps peut-être, on va pas mettre la charrue avant les bœufs ! Mais bon, à creuser.</p>
<p>Voilà pour les premières pistes pour la réalisation de ce petit plugin qui me semblerait très utile pour tout développeur sensible à la sécurité de son application (<em>aka</em> tout bon développeur !). J'attends vos remarques / suggestions / idées avec impatience !</p>
<p>PS : suivez les évolutions sur la page officielle de <a title="sfAntiBruteForcePlugin" href="http://www.symfony-project.org/plugins/sfAntiBruteForcePlugin">sfAntiBruteForcePlugin</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2010/12/projet-sfantibruteforceplugin/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Gare au whereIn !</title>
		<link>http://www.symfonic.fr/2010/10/gare-au-wherein/</link>
		<comments>http://www.symfonic.fr/2010/10/gare-au-wherein/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 17:53:14 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[array vide]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[tableau vide]]></category>
		<category><![CDATA[whereIn]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=96</guid>
		<description><![CDATA[Doctrine c'est cool, ça simplifie la vie, on n'a plus à se palucher des énormes requêtes SQL à la main, ça fait plaisir. Mais parfois c'est vicieux Doctrine. Dernier exemple en date avec la méthode whereIn(). A priori, rien de compliqué avec cette méthode, elle transforme gentiment ça : $query-&#62;whereIn&#40;&#39;id&#39;, array&#40;1, 2, 3&#41;&#41; En ça [...]]]></description>
			<content:encoded><![CDATA[<p>Doctrine c'est cool, ça simplifie la vie, on n'a plus à se palucher des énormes requêtes SQL à la main, ça fait plaisir. Mais parfois c'est vicieux Doctrine. Dernier exemple en date avec la méthode <em>whereIn()</em>. A priori, rien de compliqué avec cette méthode, elle transforme gentiment ça :</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="re1">$query</span><span class="sy0">-&gt;</span><span class="me1">whereIn</span><span class="br0">&#40;</span><span class="st0">&#39;id&#39;</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">3</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>En ça :</p>
<div class="geshi no sql">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">AND</span> id <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Mais imaginons que le tableau que vous lui passez est construit dynamiquement, et que parfois il est vide... Que se passe-t-il dans ce cas ? Avec MySQL, l'instruction "IN ()" retourne une erreur. Que fait Doctrine ? Eh bien... Rien. Il ignore le critère et effectue la requête, donnant des résultats souvent trompeurs... Une exception est censée être levée, mais une coquille dans le code fait qu'elle ne l'est pas. Un <a href="http://www.doctrine-project.org/jira/browse/DC-727" target="_blank">ticket</a> est ouvert chez Doctrine... Attention donc !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2010/10/gare-au-wherein/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>sfProjectAnalyserPlugin : est-ce que ton code est beau ?</title>
		<link>http://www.symfonic.fr/2010/09/sfprojectanalyserplugin-est-ce-que-ton-code-est-beau/</link>
		<comments>http://www.symfonic.fr/2010/09/sfprojectanalyserplugin-est-ce-que-ton-code-est-beau/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:03:21 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Intégration continue]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[sfProjectAnalyserPlugin]]></category>

		<guid isPermaLink="false">http://symfonic.fr/?p=4</guid>
		<description><![CDATA[Si tu crois être un boss de Symfony, si tu penses que ton code respecte les standards les plus stricts, si tu es sûr que toutes tes méthodes sont documentées, si tu ne fais jamais de sfContext::getInstance(), alors tu peux te mesurer au terrible sfProjectAnalyserPlugin ! Ce plugin permet en effet de mesurer la qualité [...]]]></description>
			<content:encoded><![CDATA[<p>Si tu crois être un boss de <a href="http://www.symfony-project.org/">Symfony</a>, si tu penses que ton code respecte les standards les plus stricts, si tu es sûr que toutes tes méthodes sont documentées, si tu ne fais jamais de <strong>sfContext::getInstance()</strong>, alors tu peux te mesurer au terrible <a href="http://www.symfony-project.org/plugins/sfProjectAnalyserPlugin">sfProjectAnalyserPlugin</a> !</p>
<p>Ce plugin permet en effet de mesurer la qualité et la volumétrie d'un projet. Il peut compter le nombre d'applications, de modules, d'actions d'un projet, vérifier la longueur des fonctions et des templates, lève des alertes dès qu'il repère des choses anormales, et bien d'autres choses encore.</p>
<p>Ce n'est pas juste un jouet pour sortir quelques statistiques sur son travail. Tout son intérêt réside dans son utilisation en tant qu'outil d'intégration continue. Imaginez que vous commenciez un tout nouveau projet Symfony : si chaque matin, après votre nesquik, vous lancez l'analyse de votre projet et si vous suivez les précieux conseils donnés dans la page de résultat, vous aurez au final un code beau, propre et facile à maintenir ! Vous serez alors le roi du pétrole et vous pourrez faire un énorme don aux gentils développeurs de ce plugin, sans qui vous ne seriez rien !</p>
<p>Et si vous ne le trouvez pas assez strict (ou trop strict, honte sur vous :)), pas de problème ! Il est entièrement paramétrable via son fichier YAML.</p>
<p>L'analyse se lance en une simple commande Symfony :</p>
<pre><code>symfony project:analyse --application="frontend" --env="dev" &gt; analysis.html</code></pre>
<p>Elle génère un rapport sous la forme d'un simple fichier HTML que vous pouvez bien sûr visualiser dans votre navigateur favori :</p>
<p><a href="http://www.symfonic.fr/wp-content/uploads/2010/09/sf_sandbox_analyse.png"><img class="aligncenter size-medium wp-image-74" title="sfProjectAnalyserPlugin sur sf sandbox" src="http://www.symfonic.fr/wp-content/uploads/2010/09/sf_sandbox_analyse-300x203.png" alt="sfProjectAnalyserPlugin sur sf sandbox" width="300" height="203" /></a></p>
<p>Pour davantage d'informations, rendez-vous sur <a href="http://www.symfony-project.org/plugins/sfProjectAnalyserPlugin">la page du plugin sfProjectAnalyserPlugin</a>.</p>
<p>PS : vous l'aurez peut-être deviné, je fais partie des développeurs de ce magnifique plugin ! Même si ma contribution n'a été que très modeste pour le moment... (je vais me rattraper Loïc !)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2010/09/sfprojectanalyserplugin-est-ce-que-ton-code-est-beau/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Symfony et Doctrine : connexions multiples</title>
		<link>http://www.symfonic.fr/2010/09/symfony-et-doctrine-connexions-multiples/</link>
		<comments>http://www.symfonic.fr/2010/09/symfony-et-doctrine-connexions-multiples/#comments</comments>
		<pubDate>Thu, 02 Sep 2010 20:16:06 +0000</pubDate>
		<dc:creator>Grégoire Marchal</dc:creator>
				<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Connexions multiples]]></category>
		<category><![CDATA[Doctrine]]></category>

		<guid isPermaLink="false">http://www.symfonic.fr/?p=38</guid>
		<description><![CDATA[Bon, ok, pour un premier article, je ne me lance pas dans un concept super compliqué et inconnu de tous, certes. Considérons ça comme un rodage ! Je vais donc tâcher de faire un petit article sur ma récente première utilisation de connexions multiples à des bases de données, avec Symfony 1.4 et Doctrine 1.2. [...]]]></description>
			<content:encoded><![CDATA[<p>Bon, ok, pour un premier article, je ne me lance pas dans un concept super compliqué et inconnu de tous, certes. Considérons ça comme un rodage ! Je vais donc tâcher de faire un petit article sur ma récente première utilisation de connexions multiples à des bases de données, avec Symfony 1.4 et Doctrine 1.2.</p>
<p>A la base, mon projet se connectait à une seule base, la configuration classique, la routine. Un beau jour, j'ai eu besoin d'aller mettre à jour la valeur d'un champ dans une autre base de données. Deux possibilités se présentaient :</p>
<ul>
<li>utiliser les infâmes fonctions <em>mysql_*()</em> comme dans les années 80 (bon, c'est peut-être pas si vieux, mais presque)</li>
<li>découvrir le monde merveilleux des connexions Doctrine multiples</li>
</ul>
<p>Ne m'étant jamais penché sur ce point, j'avais peur que la seconde option soit trop lourde. Mais conseillé par mes collaborateurs d'<a href="http://www.sqltechnologies.com/">SQL Technologies</a>, la tâche s'est avérée finalement très simple.</p>
<p>Premièrement, il a fallu modifier le fichier <strong>config/databases.yml</strong> afin qu'il prenne en compte la seconde connexion :</p>
<div class="geshi no yaml">
<div class="head">databases.yml</div>
<ol>
<li class="li1">
<div class="de1">all:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; connection1:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; class: &nbsp; &nbsp; &nbsp; &nbsp;sfDoctrineDatabase
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; param:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; ...
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; connection2:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; class: &nbsp; &nbsp; &nbsp; &nbsp;sfDoctrineDatabase
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; param:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; ...</div>
</li>
</ol>
</div>
<p>J'ai ensuite introspecté cette seconde base pour que Symfony génère son schéma (vous pouvez le faire à la main si vous êtes courageux !) :</p>
<div class="geshi no yaml">
<ol>
<li class="li1">
<div class="de1">symfony doctrine:build-schema</div>
</li>
</ol>
</div>
<p>Et là, magie : dans le fichier <strong>config/doctrine/schema.yml</strong>, on voit désormais que chaque table est liée à une des deux connexions grâce au paramètre... "<strong>connection</strong>" !</p>
<div class="geshi no yaml">
<ol>
<li class="li1">
<div class="de1">MyTable1:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; connection: connection1
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; columns:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ...
</div>
</li>
<li class="li1">
<div class="de1">MyTable2:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; connection: connection2
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; columns:
</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ...</div>
</li>
</ol>
</div>
<p>Et lorsque l'on reconstruit le modèle, la magie opère ! Dans les fichiers Base*.class.php du modèle, une nouvelle ligne est apparue, permettant "d'attacher" chaque classe du modèle à sa connexion :</p>
<div class="geshi no php">
<div class="head">BaseMyTable1.class.php</div>
<ol>
<li class="li1">
<div class="de1"><span class="co1">// Connection Component Binding</span></div>
</li>
<li class="li1">
<div class="de1">Doctrine_Manager<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">bindComponent</span><span class="br0">&#40;</span><span class="st0">&#39;MyTable1&#39;</span><span class="sy0">,</span> <span class="st0">&#39;connection1&#39;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
</ol>
</div>
<p>Et c'est tout ! On peut alors utiliser nos objets presque sans se soucier d'où proviennent et où vont les données.</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// stupid actions</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re1">$oObject1</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st0">&#39;MyTable1&#39;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="nu0">7</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re1">$oObject2</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st0">&#39;MyTable2&#39;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="nu0">42</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re1">$oObject2</span><span class="sy0">-&gt;</span><span class="me1">setName</span><span class="br0">&#40;</span><span class="re1">$oObject1</span><span class="sy0">-&gt;</span><span class="me1">getTitle</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
</ol>
</div>
<p>Vive Doctrine, et vive Symfony !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.symfonic.fr/2010/09/symfony-et-doctrine-connexions-multiples/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

