L'une des méthodes que l'on utilise inévitablement quand on affiche des vues de type "liste d'items" est getUserStateFromRequest.

A la différence de getUserState qui récupère le contenu d'une variable en session (classe JSession), getUserStateFromRequest effectue en premier lieu une recherche de la variable dans le formulaire ou l'URL reçue (utilisation de la méthode get de la classe Jinput).

La méthode getUserStateFromRequest existe dans 2 classes différentes JModelList et JApplication.
Leur utilisation est assez similaire, nous nous intéresserons ici à celle qui offre les fonctions les plus complètes et qui est adaptée à nos Model de vues de type liste d'éléments.

Elle est définie

  • dans JModelList en : /librairies/src/MVC/Model/ListModel.php ligne 697
  • et dans JApplication en /libraires/src/Application/CMSApplication.php ligne 560

Voici les paramètres de la méthode :


/** * Gets the value of a user state variable and sets it in the session
*
* This is the same as the method in \JApplication except that this also can optionally
* force you back to the first page when a filter has changed
*
* @param string $key The key of the user state variable.
* @param string $request The name of the variable passed in a request.
* @param string $default The default value for the variable if not found. Optional.
* @param string $type Filter for the variable, for valid values see {@link \JFilterInput::clean()}. Optional.
* @param boolean $resetPage If true, the limitstart in request is set to zero
*
* @return mixed The request user state.
*
* @since 1.6
*/
public function getUserStateFromRequest($key, $request, $default = null, $type = 'none', $resetPage = true) {

....

A noter que le dernier paramètre n'existe que dans la classe JModelList

Le parametre $request peut être de type filter_toto auquel cas on cherchera en premier lieu la variable de même nom dans le formulaire ou l'entête http, si on ne la trouve pas on effectuera la recherche dans le tableau filter de l'indice toto (filter['toto']).

Le principe de getUserStateFromRequest est le suivant :

  • Si la variable existe dans la requête http (en Post ou en Get), si sa valeur est différente de la précédente (en session) :
    • on récupère sa nouvelle valeur, et on la stocke en session.
    • s'il s’agit d'un filtre, on force la liste à revenir au début (1ère page) (si vous ne passez pas le dernier paramètre $resetPage à false)
  • Si on ne trouve pas la variable demandée dans les paramètres de la requête http ou dans le formulaire , on prend la valeur déjà stockée en session s'il y en a une.
    Ceci permet de retrouver les filtres demandés précédemment dans ce contexte (je reviendrai sur la notion de contexte plus tard).
  • Si on ne trouve pas la variable ni dans la requête http, ni dans le formulaire http, ni en session, et seulement dans ce cas on prendra la valeur par défaut passé en paramètre de la méthode.
    Il faut bien retenir cette notion qui peut ne pas sembler logique, mais vous en comprendrez la raison en lisant la suite de cet article.

Contexte de travail

La logique quand on travaille avec les variables de session, est de précéder le nom de la variable par le contexte de travail afin d'éviter les écrasements involontaires.

Il est conseillé de définir le contexte de la manière suivante : nomducomposant.nomdelavue

Le nom du contexte est généralement défini dans le constructeur de la classe du model de votre vue, mais à défaut la classe mère JModelList le calculera automatiquement dans son propre constructeur (ne pas oublier de l'appeler dans votre constructeur bien sûr).

Le nom de votre variable de session sera donc nomducomposant.nomdelavue.nomdelavariable

En session vous pouvez stocker tout type de variable, qui sera encodé en Json par le Framework (le programmeur n'aura pas à s'en inquiéter bien sûr).
Vous pouvez donc stocker des tableaux, des objets, des tableaux d'objets, etc... dans vos variables de session.

 Le nom du contexte est important, car il permet par l'utilisation de getUserStateFromRequest de retrouver l'environnement quand l'internaute revient dans une vue particulière de type liste en cours de session (donc tant qu'il reste connecté sur le site).
Ainsi il conservera ses derniers filtres, ses dernier tris et même la pagination et se retrouvera de suite sur la dernière page de cette vue qu'il aura affiché.

Si vous prédéfinissez des bornes ou des valeurs de filtres dans les paramètres des liens de menu (donc par des options spécifiques à votre vue liste, définies dans /components/votrecomposant/views/votrevue/tmpl/default.xml) et si vous utilisez un nom de contexte standard, cela vous posera donc des problèmes car on retrouvera les filtres utilisés lors du passage dans un autre lien de menu qui aura appelé la même vue.

Avec un exemple vous comprendrez mieux.

Dans un site de ligue sportive, j'ai :

  • un lien de menu vers ma vue de type liste qui permet d'afficher tous les arbitres des clubs de la ligue par département (donc avec les paramètres de vue : tous les clubs du département x)
  • un autre lien de menu vers cette même vue de type liste qui permet d'afficher tous les arbitres du club de l'utilisateur courant (donc avec paramètre : arbitre de mon club)

Il s'agit bien sûr de la même vue mais avec une configuration différente dans chaque lien de menu.

Donc avec un nom de contexte qui ne contiendra que la nom du composant et le nom de la vue, après avoir affiché les arbitres du département 68, quand l'internaute appellera la vue demandant les arbitres de son seul club, getUserStateFromRequest retournera le contenu des variables déjà en session (mis lors de l'appel du contexte précédent) et qui sera donc le numéro du département, 68 et pas le paramètre 'mon club'.

Ceci car les paramètres du lien de menu seront les valeurs par défaut qui sont les moins prioritaires (donc après celles de la requête http et de la session).

Pour régler ce problème, il faudra donc stocker autant de contextes différents que l'on a de liens de menus (avec des options de filtres différentes).
Il faudra donc rajouter Itemid (nom de la variable identifiant du lien de menu, récupérée dans la requête http par Jinput) dans le nom du contexte de votre vue liste.

Il est de aussi de pratique courante de changer de contexte selon le layout.

Donc au début de la méthode populatestate de votre model héritant de la classe mère JModelList je vous conseille de placer ceci :

 <?php
....
  protected function populateState($ordering = 'nom', $direction = 'asc') 
{ 
    $app = JFactory::getApplication();
    $input     = $app->input;
    if ($layout = $input->get('layout'))
    {
        $this->context .= '.' . $layout;
    }
    if ($Itemid = $input->get('Itemid'))
    {
        $this->context .= '.' . $Itemid;
    }
    ....
?>

Ainsi on conservera autant de contextes que de liens de menu différents accédant à cette vue.

A noter qu'il est toujours conseillé de "faire suivre"  dans vos url l'Itemid.

A lire aussi : https://docs.joomla.org/How_to_use_user_state_variables