Créer une application web avec Drupal 7 - Chapitre 3bis - Mettre en forme un tableau avec en-tetes, colonnes triées et pagination

[titre]

Les tableaux HTML sont indispensables à la présentation de données, Drupal a prévu des themes par défaut de mise en forme pour afficher les données extraites de la base. C'est la fonction theme() qui se charge de cette mise en forme. On peut utiliser theme('item-list', $data) dans les blocks (on le verra dans un chapitre ultérieur et theme('table', $data) dans les pages. Enfin, nous verrons deux autres outils de mises en forme de tableaux, le pager et le tablesort. Le but de ce chapitre 3bis est d'étendre le concept de theming de données par un exemple réutilisable ou coment mettre en forme des données tabulaires pour un affichage classique.

Les extenders

Drupal 7 enrichit les requetes à la bdd par des extender, ce sont des methodes qui agissent sur l'objet requete (d'où le grand interet de Drupal 7 qui s'enrichit d'un véritable environnement objet) pour pouvoir rendre celles-ci véritablement dynamique. On les appelle dans la requete par exemple comme ceci:

$query = db_select('node', 'n')->extend('PagerDefault')->limit(10);

on peut bien sur créer soit même ses propres extenders, ce sont des classes qui héritent de SelectQueryExtender

Exemple avec l'extender PagerDefault : source http://api.drupal.org/api/drupal/includes--pager.inc/class/PagerDefault/7

 

<?php
class PagerDefault extends SelectQueryExtender {

 
/**
   * The highest element we've autogenerated so far.
   *
   * @var int
   */
 
static $maxElement = 0;

 
/**
   * The number of elements per page to allow.
   *
   * @var int
   */
 
protected $limit = 10;

 
/**
   * The unique ID of this pager on this page.
   *
   * @var int
   */
 
protected $element = NULL;

 
/**
   * The count query that will be used for this pager.
   *
   * @var SelectQueryInterface
   */
 
protected $customCountQuery = FALSE;

  public function
__construct(SelectQueryInterface $query, DatabaseConnection $connection) {
   
parent::__construct($query, $connection);

   
// Add pager tag. Do this here to ensure that it is always added before
    // preExecute() is called.
   
$this->addTag('pager');
  }

 
/**
   * Override the execute method.
   *
   * Before we run the query, we need to add pager-based range() instructions
   * to it.
   */
 
public function execute() {

   
// Add convenience tag to mark that this is an extended query. We have to
    // do this in the constructor to ensure that it is set before preExecute()
    // gets called.
   
if (!$this->preExecute($this)) {
      return
NULL;
    }

   
// A NULL limit is the "kill switch" for pager queries.
   
if (empty($this->limit)) {
      return;
    }
   
$this->ensureElement();

   
$total_items = $this->getCountQuery()->execute()->fetchField();
   
$current_page = pager_default_initialize($total_items, $this->limit, $this->element);
   
$this->range($current_page * $this->limit, $this->limit);

   
// Now that we've added our pager-based range instructions, run the query normally.
   
return $this->query->execute();
  }

 
/**
   * Ensure that there is an element associated with this query.
   * If an element was not specified previously, then the value of the
   * $maxElement counter is taken, after which the counter is incremented.
   *
   * After running this method, access $this->element to get the element for this
   * query.
   */
 
protected function ensureElement() {
    if (!isset(
$this->element)) {
     
$this->element = self::$maxElement++;
    }
  }

 
/**
   * Specify the count query object to use for this pager.
   *
   * You will rarely need to specify a count query directly.  If not specified,
   * one is generated off of the pager query itself.
   *
   * @param SelectQueryInterface $query
   *   The count query object.  It must return a single row with a single column,
   *   which is the total number of records.
   */
 
public function setCountQuery(SelectQueryInterface $query) {
   
$this->customCountQuery = $query;
  }

 
/**
   * Retrieve the count query for this pager.
   *
   * The count query may be specified manually or, by default, taken from the
   * query we are extending.
   *
   * @return SelectQueryInterface
   *   A count query object.
   */
 
public function getCountQuery() {
    if (
$this->customCountQuery) {
      return
$this->customCountQuery;
    }
    else {
      return
$this->query->countQuery();
    }
  }

 
/**
   * Specify the maximum number of elements per page for this query.
   *
   * The default if not specified is 10 items per page.
   *
   * @param $limit
   *   An integer specifying the number of elements per page.  If passed a false
   *   value (FALSE, 0, NULL), the pager is disabled.
   */
 
public function limit($limit = 10) {
   
$this->limit = $limit;
    return
$this;
  }

 
/**
   * Specify the element ID for this pager query.
   *
   * The element is used to differentiate different pager queries on the same
   * page so that they may be operated independently.  If you do not specify an
   * element, every pager query on the page will get a unique element.  If for
   * whatever reason you want to explicitly define an element for a given query,
   * you may do so here.
   *
   * Setting the element here also increments the static $maxElement counter,
   * which is used for determining the $element when there's none specified.
   *
   * Note that no collision detection is done when setting an element ID
   * explicitly, so it is possible for two pagers to end up using the same ID
   * if both are set explicitly.
   *
   * @param $element
   */
 
public function element($element) {
   
$this->element = $element;
    if (
$element >= self::$maxElement) {
     
self::$maxElement = $element + 1;
    }
    return
$this;
  }
}
?>

Ainsi vous voyez dans le code la méthode limit (par default 10) appelée dans notre exemple par ->limit(10). Vous pouvez fouillez la doc, vous trouverez pas mal de possibilités pour customiser le PagerDefault (attention, jamais dans le source) ou pour construire votre propre extender. Je n'ai pas d'exemple en tête, mais si j'ai une idée, je vous ne ferai part (peut être quand on attaquera le cas pratique)

TableSort est le deuxième extender que nous allons utiliser permet de faire un tri sur les en-têtes du tableau, c'est également bien pratique et une fonction très web2.0 mais qui en fait ne fait pas appel au côté client. On peut trouver facilement la même chose ne javascript (avec jquery par exemple) mais je vous montre les méthodes Drupal après tout !!

la fonction theme_table

Sa doc est ici http://api.drupal.org/api/drupal/includes--theme.inc/function/theme_table. Elle s'appelle également de la manière suivante : theme('table',$data);

$data est un tableau associatif dont les clés sont:

  • header : un tableau qui contient les entêtes, soit un tableau simple, exemple 'header' => array(t('Title'), t('Type'), t('Created')) soit un tableau associatif dont les clés sont 'data', 'field', 'sort' et ce qu'on veut comme attribut html comme 'colspan' pour pouvoir regrouper des cellules.
  • rows : ce sont nos lignes de données, c'est donc un tableaux de lignes et chaque ligne est un tableau de cellules ou un tableau associatif dont les clés permettent de spécifier , 'data' la ligne de données ou un tableau permettant de spécifier chaque cellule ainsi que la classe CSS, le colspan etc.., 'class' une classe CSS et 'no-stripping' de ne pas avoir l'alternance de lignes de fond.. Un peu compliqué comme ça mais lisez la doc, on s'en sort, la plupart des erreurs viennent de la structure des arrays.
  • attributes : un tableau d'attributs HTML à appliquer à la balise
    comme par exemple 'attributes' => array('class'=>array('monjolitableau'), 'border =>'1px solid black')
  • caption : une chaine qui s'applique à la balise HTML
  • colgroups: Un tableau de groupes de colonnes. Chaque élément du tableau peut être soit:
    • Un tableau de colonnes, dont chacune est un tableau associatif d'attributs HTML appliquée à l'élément COL.
    • Un tableau de clés appliqués à l'élément COLGROUP, qui doit inclure une clé "data". Pour ajouter des attributs aux éléments COL, définissez la clé "data" avec un tableau de colonnes, dont chacune est un tableau associatif d'attributs HTML.

    Un exemple:

    <?php
        $colgroup
    = array(
         
    // COLGROUP with one COL element.
         
    array(
            array(
             
    'class' => array('funky'), // Attribute for the COL element.
           
    ),
          ),
         
    // Colgroup with attributes and inner COL elements.
         
    array(
           
    'data' => array(
              array(
               
    'class' => array('funky'), // Attribute for the COL element.
             
    ),
            ),
           
    'class' => array('jazzy'), // Attribute for the COLGROUP element.
         
    ),
        );
       
    ?>

    Ces balises facultatives sont utilisées pour grouper et définir des propriétés sur les colonnes d'une table. Par exemple, on peut facilement grouper trois colonnes et appliquer le même style de fond à toutes.

  • sticky : pour que les en-têtes du tableau soient collants, c'est à dire tout le temps affiché (javascript)
  • empty : Une chaine à afficher si la cellule est vide

Exemple

On repart sur notre exemple d'articles hebdomadaires: la callback de la page commence de la manière suivante :

<?php
function articles_hebdo_page_callback(){
$today = getdate();    //Date il y a une semaine
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);    //Obtient tous les messages depuis une semaine jusqu'à aujourd'hui.
$end_time = time();
?>

On définit les entetes et les champs à récuperer dans la BDD

<?php
$header
= array(
    array(
'data' => t('Title'), 'field' => 'title', 'sort' => 'asc'),
    array(
'data' => t('Node ID'), 'field' => 'nid'),
    array(
'data' => t('Type'), 'field' => 'type'),
    array(
'data' => t('Created'), 'field' => 'created'),
    array(
'data' => t('Published')),
    );
$fields = array ('nid', 'title', 'type', 'created', 'status');
?>

On récupère les données via la fonction _articles_hebdo_contents($header, $fields)

<?php
$results
= _articles_hebdo_contents($header, $fields); // on récupère les données
?>

La fameuse fonction avec les extenders PagerDefault (anciennement une focntion pager_query dans Drupal 6) et Tablesort (anciennement une chaine à rajouter à la chaine sql dans Drupal 6)

<?php
/**
* fonction de chargement des articles de la semaine
* @param :
* $header : un tableau d'entêtes
* $fields : les champs associés
*
* @return
*   Un  objet SelectQuery
*/
function _articles_hebdo_contents($header = array(), $fields = array()){
//Date d'aujourd'hui
$today = getdate();
//Date il y a une semaine
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Obtient tous les messages depuis une semaine jusqu'à aujourd'hui.
$end_time = time();

//Utilise le databaseAPI pour trouver les resultats
$query = db_select('node', 'n')
->
extend('PagerDefault')->limit(10)
->
condition('status', 1) //Publié.
->condition('type', 'article')
->
condition('created', array($start_time, $end_time), 'BETWEEN')
->
extend('TableSort')->orderBy('created', 'DESC') //Tri du plus recent au plus ancien.
->fields('n', $fields)
->
execute();
return
$query;
}
?>

On prépare un tableau pour les lignes et on fait une boucle sur les résultats de la fonction _articles_hebdo_contents($header, $fields)

<?php
$rows
= array();
foreach (
$results as $node) {
   
$rows[] = array(
       
'data' => array(
           
l($node->title, 'node/'. $node->nid .'/view'),
           
$node->nid,
           
$node->type,
           
format_date($node->created,'custom','d/m/Y','Europe/Paris','fr'),
           
$node->status
           
)
    );
}
?>

Il nous reste plus qu'à préparer la fonction theme_table et le pager

<?php
$data
= array(
   
'header' => $header,
   
'rows' => $rows,
   
'sticky' => TRUE,
   
'caption' =>'<h3>'.t('Articles de la semaine du ').strftime('%d/%m',$start_time).t(' au ').strftime('%d/%m',$end_time).'</h3>',
   
'attributes' => array('class' => array('mytable')),
   
'empty' => t('Données non disponibles')
    );
$content = theme('table', $data);
$content .= theme('pager');
return
$content;
?>

Conclusion

Voila en quelques lignes une mise en forme parfaite, il reste à faire la feuille CSS pour une apparence personnalisée. Je note qu'on peut utiliser une fonction de thème ou un template intermédiaire entre la callback et la fonction theme_table, c'est le genre de chose qu'on pourrait faire pour la page des utilisateurs récemment inscrits et connectés par exemple. Je met les sources de l'exemple de l'article en fichier attaché. Faites des essais surtout pour les attributs et les colspan et si quelque chose ne marche pas, regardez le source de la fonction theme_table, c'est le meilleur moyen d'apprendre comment le truc fonctionne

Fichier attachéTaille
list_recent.zip3.02 Ko

fake oakley sunglasses

Fake oakley sunglasses is made of the most trendy style. cheap oakley sunglasses carryies on the complete explanatory notes that are comfort, fit, function, duarablity and practicality. Fake oakleys make every effort to give the wearers surprise and comfort and enjoyment. cheap oakleys must become your favourite in the future.With high-tech element and exquisite craft, Oakley has become people's perfect luxury eye wears. oakley sunglasses is one of the largest brands in sunglasses and has a variety of products which appeal across the board to many kinds of people. Wearing a pair of Fake oakley will certainly show your unique style.

cheap oakley sunglasses

cheap oakley sunglasses are sold here for all age groups and come in a complete array of shades, models and styles.At our oakley outlet, you can buy discount oakley sunglasses with high quality, save up to 70%, and these are some colorful oakley sunglasses cheap styles you can choose. Now get top quality fashion oakley sunglasses discount that suit your mood.If you are searching for oakley sunglasses outlet online.

oakley frogskins fire iridium

people were shocked, black most oakley sunglasses on sale of his face, even the fragrance is quite a big jump. People in the war, she was going to do? oakley m frame Help screaming? However, she really missed her husband! And maybe she will help busy, such as Cook big, laundry oakley frogskin blue iridium to mend his clothes, or taking care of injuries and the like, although she didn't tell my second brother studied, but the most basic wound treatment of her. So, she should be able to oakley frogskins pink sunglasses go? "But the sth Sth Sister-in-law, Lord very hard on the battlefield! "Changing Chui stammered, eat eggs were kept.

Stupid pigs, not to michael

Stupid pigs, not to michael kors signature toteeat tonight! "" The witch, I'm a frog, not a pig, do not always callmichael kors grayson you stupid pig for me? "Kaka says with a trembling all over, because he michael kors handbags sale was very afraid of the old witch. "Roll, roll! I give you the flower mandala, help you to

michael kors outlet handbags

michael kors bags on sa catch small animals, michael kors outlet you dumb pig, do something!

That discount ray ban

That discount ray ban sunglasses rep offers quite lately improved the range connected with ray ban outlet. That website is quite user-friendly ray ban sunglasses clearance so you can simply steer towards page you desire ray ban sunglasses outlet. In order to buy a custom made couple of wayfarer sunglasses sale from an inexpensive value then you definately must bounce on to your own ray ban wayfarer sale shops website cheap ray ban aviator.

nike air max 1 sale

If you had to pick one type or series of nike air max 1 to wear exclusively for the rest of your life which one do you think you would pick? Would it be a shoe from Nike like the nike air max 1 sale or the Dunk? Or from another company altogether? Personally if you were to ask us then we would probably have to go with the Nike Air Max series simply for the fact that there is so much choice and so many options involved with the Air Max series.

These discount oakley sunglasses are manufactured with good technology. It also protects your eyes from water surface and sun rays. cheap oakley sunglasses was established in 1975. This company not only manufactures Oakley Sunglasses.

sMaurinePrudencea

Nor did William attempt, as the water heater leak is regularly visualised to have accomplished, to root out the old associations of England, and to set up in their position either the pre-existing associations of Normandy or perhaps some new organizations of his individual contriving. Six hundred years later came troops of fighters with jaws plugged with bizarre oaths, cursing their invaders. Seven of tankless gas water heaters the panels of many of these rooms looked down in to the garden; and all of us have stayed up there altogether plenty a summertime eve, stating exactly how pleasant it was, and conferring of plenty elements. So, A Place Tradesman, addressing the public in 1878, in a pamphlet entitled 'The Historic Exchanges decayed, repaired all over again,-wherein are announced the some abuses that have altogether weakened all of the old exchanges in the Country,' urges that the boss cause of the evil had been the setting up of Stage-coaches some eighty tankless water heater reviews years before. In the event this brilliant blanket of pebbles, without encompassing the mud definitely produced by reliance water heaters their attrition, was piled in to a mound, it should type a big hill string!

gDoretheaElvax

The fact is, Mr Black, you need to find yet another site for your own brick block, and be content to retreat my own manor with the present owner. We all almost all pledge ourselves to be adequate to persist to delight. The case britax roundabout 55 had been brought in to the Police Court, and verdict provided in her favour, Still the guilty 1 had stashed, and his parent wouldn't manifest his whereabouts. Many of us launched on this post in November, 1907, and through the interval it was being worked at or alternatively over by one of some britax marathon 70 dozen boys. a number of us have delayed too long, and can darken our story too immediately. We're married. His stories were clearly monstrous, disunited, and without aim; but they were interested on the basis of a vein of human tenderness which sailed by all of them, and was along the lines of a sweet, familiar front, experienced amidst wild and graco comfort sport unearthly scenery. But as the thought process in a human being is above the belly, so the intellect in a woman is above the bare maternal attention inspired by babyhood.

In 2002, the Tambour watch

In 2002, the Tambour watch replica louis vuitton purses collection was introduced. During this cheap ralph lauren polo year, the cheap louis vuitton LV building in Tokyo's Ginza district was opened, and ralph lauren shirts the brand collaborated with ralph lauren polo Bob Wilson for louis vuitton replica handbags its Christmas windows ralph lauren polo store sceneography. In 2003, Takashi Murakami, in imitation louis vuitton collaboration with Marc fake louis vuitton Jacobs, masterminded the new Monogram Multicolore canvas range of cheap ralph lauren handbags and accessories. This range included the monograms of the standard Monogram Canvas, but in 33 different replica louis vuitton colors on either louis vuitton replica bags a white or black background.  Murakami also created ralph lauren cheap the Cherry Blossom pattern, in which smiling cartoon faces in the middle louis vuitton luggage replica of pink and yellow louis vuitton replica flowers were sporadically placed atop the Monogram cheap ralph lauren polos Canvas. This pattern appeared on a cheap louis vuitton replica limited number of pieces. replica louis vuitton bags The production of this limited-edition run was discontinued in June 2003. replica louis vuitton handbags Within 2003, the stores in Moscow, Russia and in New Delhi, India were opened, the Utah and Suhali louis vuitton luggage replica cheap leather lines were released, and the ralph lauren polo shirts 20th anniversary of the LV Cup was held. louis vuitton fake

Ever wonder if your priceless

Ever wonder if your priceless exotic car ralph lauren polos really looks great? Ralph Lauren knows which jordan shoes ones do.


Ralph Lauren runs his own billion-dollar company, grew up in a middle-class neighborhood where the high ralph lauren polo school was an archetypal blue-collar 50’s “Grease”-era institution, and Ralph Lauren started his jordan shoes for sale business relying on his jordan retro belief in his ability ralph lauren big pony to ralph lauren polo shirt turn polo ralph lauren uk normal schmucks into ralph lauren uk people who looked and felt like discount ralph lauren polo shirts the world’s ralph lauren polo big pony elite.


Every day in the late 1950s nike air jordan retro young Ralph Lifshitz did a double-take during his pedestrian commute in New York City ralph lauren polo sale to nike jordan shoes his job ralph lauren outlet selling ties polo ralph lauren outlet at Brooks Brothers ralph lauren sale as he passed import polo by ralph lauren car dealer showrooms. Ralph ralph lauren t shirts Lauren's car nut side developed air jordan retro at that air jordan shoes time, when he hoofed his cheap jordan shoes way through Manhattan passing Jaguar and Morgan shops at a ralph lauren polo uk time polo ralph lauren when not many places in the U.S. cheap jordan had those rare imports on display. Ralph Lauren thought the cars nike air jordan were beautiful.

Publier un nouveau commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.
CAPTCHA
Cette question vous est posée pour savoir si vous êtes un humain ou un robot de SPAM.
Image CAPTCHA
Saisir les caractères affichés dans l'image.