mars
2010
L’aide de contrôleur qu’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’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’une même vue se heurtera à un problème que l’on abordera ici.
Cette (courte) série d’articles aura pour but de pointer du doigt quelques problématiques concrètes d’utilisation des helpers ContextSwitch et AjaxContext. Pour plus d’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
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’une utilisation au sein d’un formulaire dynamique, nous génèrerons ces données sous forme d’une liste select dans l’éventualité d’un appel Ajax.
Voici le code de notre controller :
{
$this->_helper->contextSwitch
->addActionContext('index', 'xml')
->initContext();
$this->_helper->AjaxContext
->addActionContext('index', 'html')
->initContext();
}
public function indexAction ()
{
$this->view->data = array(
'value1' => 'text1',
'value2' => 'text2',
'value3' => 'text3',
'value4' => 'text4',
);
}
Et voici nos vues :
<?php foreach ($this->data as $value => $text) : ?>
<div id="<?php echo $this->escape($value); ?>">
<?php echo $this->escape($text); ?>
</div>
<?php endforeach; ?>
// index.xml.phtml
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>
<root>
<?php foreach ($this->data as $value => $text) : ?>
<row>
<value><?php echo $this->escape($value); ?></value>
<text><?php echo $this->escape($text); ?></text>
</row>
<?php endforeach; ?>
</root>
// index.ajax.phtml
<?php echo $this->formSelect('data', null, null, $this->data); ?>
Et voici le retour que l’on aurait pour chacune de ces vues :
<div id="value1">text1</div>
<div id="value2">text2</div>
<div id="value3">text3</div>
<div id="value4">text4</div>
// format == xml
<?xml version="1.0" encoding="utf-8" ?>
<root>
<row>
<value>value1</value>
<text>text1</text>
</row>
<row>
<value>value2</value>
<text>text2</text>
</row>
<row>
<value>value3</value>
<text>text3</text>
</row>
<row>
<value>value4</value>
<text>text4</text>
</row>
</root>
// Appel Ajax, format == html
Exception information:
Message: Context "html" does not exist
Inutile de préciser que ce n’était pas trop le résultat attendu… 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.
La première chose, est qu’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’une séance de debug, l’on se rends compte que l’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.
A ma connaissance, il n’existe pas de manière de modifier ce comportement, et même si il m’aurait paru plus logique qu’en présence d’une requête Ajax l’helper AjaxContext prenne le dessus sur le ContextSwitch, je me plais à croire qu’il y a une raison valable à tout ça. A ce sujet, si quelqu’un bout dispose d’un élément de réponse, je suis preneur
La solution la plus simple que j’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 :
->addActionContext('index', 'html')
->setContextParam('ajax')
->initContext();
Désormais, plus de conflit, il suffit de spécifier /Ajax/html dans l’url de notre requête Ajax et tout marchera correctement. En espérant que ça dépanne quelqu’un qui un jour se serait retrouvé confronté au problème
Je pense en effet que cela marcherait, mais on ne bénéficierait plus de l’action de l’AjaxContext, à savoir s’assurer que la requête est bien une requête Ajax avant de servir son contenu… Ce n’est certes pas la plus indispensable des fonctionnalités, mais ça rajoute une très faible sécurité supplémentaire.
peut etre que cela marcherai
autant pour moi mon pdfContext étend contextSwitch mais si je lui fait étendre AjaxContext il ne marche plus. cela viens sans doute de
Merci pour ce commentaire
J’ai eut pendant un moment un affreux doute, mais après quelques tests je me rends compte que non. Si je reprends l’exemple et que j’utilise uniquement l’AjaxContext pour définir mes deux contextes xml et html, alors oui j’aurais bien accès aux formats xml et html, mais uniquement dans le cas d’un appel Ajax.
Si j’appelle directement /index/index/format/xml, j’aurais la sortie « classique » en réponse. Par contre mon formulaire Ajax me retourne bien du xml ou une liste select en fonction du paramètre format.
A titre informatif, j’effectue mes tests sur la 1.10.2, mais je ne pense pas que le comportement ait changé récemment.
AjaxContext étends de ContextSwitch donc il suffit de faire
ou meme
Peut etre que je dis une bétise mais chez moi ca marche. J’ai créer un nouveau helper pour prendre en charge mes PDF . il étends ContextSwitch et gere encore l’ajax (au format json).