Extension du Doctrine Routing Object
By Mathieu on Monday, May 18 2009, 10:12 - Symfony - Permalink
Pour mon premier billet je vais vous parler du routing de symfony, pour être plus précis du routing des objets doctrine.
Le problème auquel je me suis confronté était le suivant : La classe sfDoctrineRoute recherche à chaque fois, s'il existe une méthode pour récupérer le paramètre de l'objet demandé dans la règle de routage, même si le paramètre est renseigné manuellement.
Exemple du problème :
Nous avons des articles composés de plusieurs pages.
On a auparavant créé une méthode getRank(), qui retourne la première page de l'article, celle-ci est dédiée pour le routing
Le fichier de routing
article_show:
url: /article/:id/page/:rank.html
class: sfDoctrineRoute
options: { model: Article, type: object }
param: { module: article, action: show }
requirements:
id: \d+
rank: \d+
sf_method: [get]
Lien généré ($article est une instance de Article) :
url_for('article_show', $article)
Résultat attendu : /article/1/page/1.html
Résultat obtenu : /article/1/page/1.html
url_for('article_show', array('sf_subject' => $article, 'rank' => 2))
Résultat attendu : /article/1/page/2.html
Résultat obtenu : /article/1/page/1.html
On remarque donc que la règle de routing n'a que faire de notre paramètre rank, il sera toujours alimenté par la méthode getRank() de l'objet Article.
Pour réglé ce problème auquel je n'ai pas trouvé de solution sur la Mailing List, j'ai donc décidé d'étendre la classe sfDoctrineRoute, pour que lorsque l'on fourni un paramètre manuellement celui-ci ne soit pas écrasé, par celui récupéré par la méthode de l'objet.
/**
* myDoctrineRoute
*/
class myDoctrineRoute extends sfDoctrineRoute
{
protected function convertObjectToArray($object)
{
if (is_array($object))
{
if (!isset($object['sf_subject']))
{
return $object;
}
$parameters = $object;
$object = $parameters['sf_subject'];
unset($parameters['sf_subject']);
}
else
{
$parameters = array();
}
if(isset($this->options['erase']) && $this->options['erase'] === false)
{
$response = array_merge($parameters, $this->doConvertObjectToArray($object));
}
else
{
// We check the parameters value and unset them if they are null
// We define an array of null values and we check if exist one to do the foreach, to unset the null values
$nullValues = array(null, 'null');
$findNull = true;
$iFindNull = 0;
while($iFindNull < count($nullValues) && $findNull === false)
{
$findNull = in_array($nullValues[$iFindNull], $parameters);
$iFindNull++;
}
if($findNull)
{
foreach($parameters as $parameterKey => $parameterValue)
{
if(in_array($parameterValue, $nullValues))
{
unset($parameters[$parameterKey]);
}
}
}
$response = array_merge($this->myDoConvertObjectToArray($object, $parameters), $parameters);
}
return $response;
}
protected function myDoConvertObjectToArray($object, $defaultParameters = array())
{
if (isset($this->options['convert']) || method_exists($object, 'toParams'))
{
return parent::doConvertObjectToArray($object);
}
$className = $this->options['model'];
$parameters = array();
foreach ($this->getRealVariables() as $variable)
{
if(!in_array($variable, array_keys($defaultParameters)))
{
try {
$parameters[$variable] = $object->$variable;
} catch (Exception $e) {
try {
$method = 'get'.sfInflector::camelize($variable);
$parameters[$variable] = $object->$method;
} catch (Exception $e) {}
}
}
}
return $parameters;
}
}
Après cela il faut donc changé notre de règle de routing, avec en bonus un paramètre pour définir le comportement de votre règle, si celle-ci doit écrasé les paramètres renseignés manuellement ou non, à l'aide de l'option erase qui par défaut est à true:
article_show:
url: /article/:id/page/:rank.html
class: myDoctrineRoute
options: { model: Story, type: object, erase: true }
param: { module: story, action: index }
requirements:
id: \d+
rank: \d+
sf_method: [get]
N'hésitez pas maintenant à me faire part de vos impressions, car je pense qu'il existe déjà une solution et j'ai d'ailleurs trouvé cela étrange de ne pas la trouver.
Comments
Hors sujet.
Vous utilisez le super plugin cycle basé sur jquery pour réaliser le slideshow. Sur mon propre site je viens juste de découvrir pourquoi les diverses images du cyle sont visible simultanément lors du chargement de la page.
Pour éviter ce comportement, il suffit d'inscrire le header dans un div de la hauteur des images ( 180px dans votre cas ) et de lui appliquer le style overflow:hidden;. De cette manière, dès le chargement de la page, une seule image est visible.
Cordialement,
RG
Merci pour l'astuce :p
Cordialement,
Mathieu.
<A href="http://www.toptoys2trade.com/zhu-zh... ">zhu zhu pets</A>
<a href="http://www.toptoys2trade.com/a-sill... "> silly bandz</a>
<A href="http://www.toptoys2trade.com/power-... "> power balance</A>
<A href="http://www.toptoys2trade.com/animal... ">animal rubber bands</A>
<A href="http://www.toptoys2trade.com/baby-c... ">Baby Carriers</A>
<A href="http://www.toptoys2trade.com/pillow... ">Pillow Pets</A>
<A href="http://www.toptoys2trade.com/plush-... ">Plush Pencil Case</A>