Ajouter des filtres sur une liste

Introduction

A partir de Dotclear 2.20 il est possible pour un plugin d'ajouter des filtres sur des listes qu'il pourrait créer dans ses pages d'administration. Il est également possible d'ajouter des préférences utilisateur sur l'ordre de tri et le nombre de résultats affichés par page.

Préférences utilisateurs

Nous allons commencer par ajouter à notre liste de résultats deux préférences utilisateur, le choix des colonnes à afficher et les options de tri par défaut.

Déclaration dans _admin.php

Deux behavior doivent être déclarés dans le fichier _admin.php :

<?php
if (!defined('DC_CONTEXT_ADMIN')) {
    return;
}
 
# Annonce que monPlugin a des préférences utilisateur sur les colonnes
$core->addBehavior('adminColumnsLists', 'monPluginAdminColumnsLists');
 
/**
 * Choix de colonnes
 * 
 * @param  dcCore       $core   core instance
 * @param  arrayObject  $cols   Toutes les préférences de colonnes
 */
function monPluginAdminColumnsLists($core, $cols)
{
    // identifiant de cette préférence de colonne
    $cols['monplugin'] = [
        // Titre à afficher sur la page d'administration des préférences utilisateur
        __('Mon plugin'),
        [
            // Une colonne que l'utilisateur peut cacher.
            'date' => [true, __('Date')],
            // Une autre
            'author'     => [true, __('Author')],
            // une autre qui sera cachée par défaut
            'comments'   => [false, __('Comments')],
            // 'identifiant' => [afficher par défaut, Nom]
            'trackbacks' => [true, __('Trackbacks')]
        ]
    ];
}
 
# Annonce que monPlugin a des préférences utilisateur sur les options de tri
$core->addBehavior('adminFiltersLists', 'monPluginAdminFiltersLists');
 
/**
 * Options de tri
 * 
 * @param  dcCore       $core   core instance
 * @param  arrayObject  $cols   Toutes les préférences de tri
 */
function monPluginAdminFiltersLists($core, $sorts)
{
    // identifiant de cette préférence de tri
    $sorts['monplugin'] = [
        // Titre à afficher sur la page d'administration des préférences utilisateur
        __('Mon plugin'),
        // Liste de choix de colonne de tri
        [
            // nom => identifiant (généralement le paramètre de la requête sql)
            __('Date') => 'post_dt',
            __('Author') => 'user_id'
        ],
        // choix par défaut, un des identifiants de choix précédent
        'post_dt',
        // ordre de tri par défaut (généralement asc ou desc)
        'desc',
        // nombre de résultats par page: titre, nombre
        [__('entries per page'), 30]
    ];
}

Identifiants réservés par Dotclear: posts, comments, blogs, users, media, search, et le plugin pages. Ces quelques lignes de codes suffisent à gérer les préférence utilisateur pour la liste de notre plugin. Si on souhaite n'utiliser que le nombre de résultats par page, sans notion de tri, la fonction s'écrira alors avec des valeurs égales à null: <code php> function monPluginAdminFiltersLists($core, $sorts) { identifiant de cette préférence de tri

  $sorts['monplugin'] = [
      // Titre à afficher sur la page d'administration des préférences utilisateur
      __('Mon plugin'),
      // pas de liste de choix de colonne de tri
      null,
      // pas de choix par défaut
      null,
      // pas d'ordre de tri
      null,
      // nombre de résultats par page: titre, nombre
      [__('entries per page'), 30]
  ];

} </code>

Construction du filtre de liste

La liste et le filtre de notre plugin seront affichés depuis la page index.php

Déclaration du filtre global

Dans le fichier index.php de notre plugin, la ligne suivante permet de créer l'objet qui va gérer les filtres tout au long du code:

<?php
 
if (!defined('DC_CONTEXT_ADMIN')) {
    return;
}
 
// création du filtre global
$mon_filtre = new adminGenericFilter($core, 'monPlugin');

Ici le filtre générique est utilisé, si on veut aller plus loin et créer un objet spécialement conçu pour un plugin plus avancé, il faut que la class étende adminGenericFilter, on peut reprendre les exemples des filtres internes à Dotclear (billets, commentaires, blogs, …) qui sont présents dans le fichier dotclear/inc/admin/lib.adminfilters.php

Déclaration et ajout d'un filtre champs

Un filtre champs correspond à un champ comme celui du choix d'auteur, de catégorie, de format sur la liste des billets d'un blog. Ce filtre récupère ce dont il a besoin soit dans l'url de la page, soit dans les préférences utilisateur, soit dans ces paramètres par défaut, il gère son affichage (le champ), il gère ce qu'il va renvoyer comme paramètre de requête pour l'affichage de la liste.

Il doit être un objet dcAdminFilter. Pour créer un filtre on peut suivre la méthode suivante:

$combo_options = [
    __('round')  => 'r',
    __('square') => 's'
];
 
$filtre_format = new dcAdminFilter('monformat');
$filtre_format->title = __('Format:');
$filter_format->type = 'select';
$filter_format->options = $combo_options;
$filter_format->prime = true;
$filter_format->param = 'fmt';

Une façon raccourcie d'écrire la même chose :

$filtre_format = (new dcAdminFilter('monformat'))
    ->title(__('Format:'))
    ->type('select')
    ->options($combo_options)
    ->prime(true)
    ->param('fmt');

Explication:

  • on crée un filtre d'id monformat,
  • on lui donne le titre Format:, c'est le titre du champ qui sera affiché,
  • on indique qu'il sera de type select (combo),
  • on ajoute les choix qui seront proposés,
  • on indique qu'il sera placé dans la première colonne avec prime = true (il sera dans la seconde avec false)
  • enfin la clé du paramètre de recherche qu'il renverra pour la requête de liste sera fmt

Un filtre champs supporte deux type de champ : input comme par exemple un champ de recherche et select pour une liste de choix. On peut lui passer directement du code html avec la requête

$filtre_format->html('mon code html');

Il est possible de ne pas spécifier de type, le filtre transmettra simplement sa valeur sans rien afficher, il est également possible à tout moment de forcer sa valeur pour cela on peut spécifier

$filtre_format->value('xxx');

ou directement lors de sa création avec

$filtre_format = new dcAdminFilter('monfiltre', 'xxx');

Pour ajouter ce filtre champ au filtre global, il suffit d'utiliser la commande suivante :

$mon_filtre->add($filtre_format);

Dans le cas d'un simple filtre, on peut directement le créer dans la commande d'ajout avec :

$mon_filtre->add('filtre_format', 'xxx');

Il existe des filtres pré-écrits comme celui de la gestion de la page courante getPageFilter() pour une liste de plusieurs pages ou encore getSearchFilter() pour un champ de recherche. On les ajoute directement avec la fonction add :

$mon_filtre->add(dcAdminFilters::getSearchFilter());

Récupération des paramètres de requête

Afin de préparer la requête qui va permettre d'afficher notre liste, il faut récupérer les paramètres liés aux filtres, pour cela on utilise la commande suivante :

$params = $mon_filtre->params();

Avec le filtre qu'on a ajouté et les paramètres de préférence utilisateur, le tableau de paramètres devrait ressembler à ça :

Array(
    'sortby' => 'post_dt',
    'order'  => 'desc',
    'nb'     => 30,
    'fmt'    => ''
);

Il est possible de modifier la façon dont sera traitée la valeur d'un filtre champ avant qu'il soit retourné en paramètre, c'est avec la commande $filtre_format→param(); vue précédemment. 3 cas sont possibles :

1) Paramètre par défaut :

Si on ne précise pas la commande →param(), le paramètre prend comme clé l'identifiant du filtre et comme valeur celle par defaut, c'est à dire la valeur spécifiée lors de la création du filtre ou la valeur de $_GET[identifiant]. Cela équivaut à écrire :

$filtre_format->param();

2) Paramètre par défaut avec une clé spécifique :

La plupart du temps on utilise comme identifiant la clé de paramètre, c'est plus simple pour s'y retrouver, mais on peut les différencier en précisant une clé de retour comme vue précédemment avec :

$filtre_format->param('fmt');

3) Paramètre spécifique :

Il est possible de traiter de façon spéciale la valeur à retourner en précisant en second paramètre de la commande →param() une fonction de traitement, par exemple :

$filtre_format->param('fmt', 'ma_function_speciale');
 
function ma_function_speciale($filtres)
{
    if ($filtres[0] != '') {
        return "AND post_fmt = ' . $filtres[0] . ", " . $filtres['cat_id'] . "' ";
    }
    return '';
}

La fonction de traitement prend en paramètre un tableau de toutes les paires clé/valeur des filtres. Avec en clé 0 la valeur du paramètre du filtre courant. Dans cet exemple, si le paramètre du filtre courant (qui a appelé notre fonction) n'est pas vide, on créé une portion de code sql. La commande accepte une fonction anonyme qui permet d'écrire :

$filtre_format->param('sql', function ($f) { 
    return !empty($f[0]) ? "AND post_fmt = ' . $f[0] . ", " . $f['cat_id'] . "' " : ''; 
});

Clés spéciales :

Il y a plusieurs clés spéciales qui permettent de compléter les paramètres, ce sont les clés columns, from, where, sql.

  • La clé columns retournera un tableau des valeurs des filtres ayant ce paramètre.
  • Les clés from, where, sql mettront bout à bout toutes les valeurs des filtres ayant ce paramètre.

Par exemple en ajoutant (inutilement) des colonnes à ce qui a été fait précédemment :

$mon_filtre->add('columns', 'post_plop');
$mon_filtre->add('columns', 'user_truc');
 
$params = $mon_filtre->params();

On obtiendrait le tableau suivant :

Array(
    'columns' => ['post_plop', 'user_truc'],
    'sortby'  => 'post_dt',
    'order'   => 'desc',
    'nb'      => 30,
    'sql'     => "AND post_fmt = 's, 2' "
);

Pour aller plus loin

Voici quelques astuces pour gagner du temps.

Si votre plugin affiche une liste de billets similaire à celle des billets Dotclear, il est possible de reprendre entièrement les filtres en indiquant le nouveau type de billets :

$mesbillets_filtre = new adminPostFilter($core, 'mesbillets', 'mon_post_type');

Ceci chargera tous les filtres associés aux listes de billets. Et si votre plugin ne veut pas de catégorie, il suffit d'enlever juste après ce filtre avec :

$mesbillets_filtre->remove('cat_id');

Autre astuce, vous pouvez charger plusieurs filtres en une fois :

$filtres[] = new dcAdminFilter('part', 'plop');
//...du code
$filtres[] = (new dcAdminFilter('plop'))->title('plop')->param('plooop');
//...du code, etc
$mesbillets_filtre->add($filtres);

Affichage du filtre et de la liste

Affichage du filtre

L'affichage du filtre se fait en deux temps :

1) entête javascript :

Il faut dans un premier temps charger les fonctions javascript qui se chargent de gèrer la zone dépliable, de la mise à jour des préférences utilisateur sur les options de tri, de la remise à zéro des filtres. Pour cela dans la balise <head> de notre page index.php il faut ajouter la ligne :

echo $mon_filtre->js($url);

L'url sera celle de l'affichage de la page de liste par défaut. Si la page de la liste est celle d'arrivée de votre plugin, alors son url est :

$url = $core->adminurl->get('admin.plugin.monPlugin');

Pour faire plus compliqué, si votre liste est dans une sous partie, avec des onglets, l'url s'écrira par exemple :

$url = $core->adminurl->get('admin.plugin.monPlugin', ['part' => 'ma_liste'], '&') . '#entries;

Mais ce n'est pas le sujet ici :)

2) Affichage du filtre global :

L'affichage se fera avec le même aspect que sur tous les filtres de listes dans Dotclear avec la commande suivante :

$post_filter->display('admin.plugin.monPlugin');

Il n'y a pas besoin de faire un echo devant l'appel. La fonction →display() prend un premier paramètre obligatoire qui est l'url de base de la page utilisant la notation de la fonction $core→adminurl→get(). Et si votre liste est dans un onglet, il faut alors l'écrire :

$post_filter->display(['admin.plugin.monPlugin','#entries']);

La fonction display peut prendre un second paramètre optionnel qui est une chaîne de caractères qui sera directement inclue dans l'affichage html du filtre global. Cela peut servir pour ajouter des champs cachés. (créés avec form::hidden()).

Affichage de la liste

On ne détaille pas ici l'affichage de la liste de résultats, mais seulement des astuces inhérentes aux filtres.

Si on prend l'exemple de la listes des billets Dotclear (admin/posts.php) :

# filters
$post_filter->display('admin.posts');
 
# Show posts
$post_list->display($post_filter->page, $post_filter->nb,
    '<form action="' . $url . '" method="post" id="form-entries">' .
 
    '%s' .
 
    '<div class="two-cols">' .
    '<p class="col checkboxes-helpers"></p>' .
 
    '<p class="col right"><label for="action" class="classic">' . __('Action:') . '</label> ' .
    form::combo('action', $posts_actions_page->getCombo()) .
    '<input id="do-action" type="submit" value="' . __('ok') . '" disabled /></p>' .
    $core->adminurl->getHiddenFormFields('admin.posts', $post_filter->values()) .
    $core->formNonce() .
    '</div>' .
    '</form>',
    $post_filter->show()
);
}

On peut voir que la page courante est issue des filtres avec $post_filter→page, idem pour le nombre de résultats par page avec $post_filter→nb.

On a remplacé la quinzaine de form::hidden('xxx', 'yyy'); par une seule ligne :

$core->adminurl->getHiddenFormFields('admin.posts', $post_filter->values())

Avec $post_filter→values() qui contient déjà toutes informations sous forme de tableau.

Enfin, $post_filter→show() permet de préciser si les filtres par défaut ont été modifiés. …

Wiki powered by Dokuwiki.