lundi 20 juin 2011

CGridView : formater les cellules

Dans un précédent post, nous avons vu comment il est possible de définir ce qui sera affiché dans les colonnes du widget CGridView. Le principe consistait à décrire sous la forme d'un tableau associatif, ce que Yii allait devoir afficher dans une colonne donnée. La valeur du paramètres 'value' en particulier, est évalué par Yii et c'est le résultat de cette évaluation qui est affiché dans la colonne.
C'est bien....
C'est bien mais ça peut devenir vite rébarbatif à écrire surtout si la valeur de la colonne est le résultat d'une expression complexe.. on s’emmêle vite les pinceaux entre les guillemets simples, doubles ... bref, c'est pas la joie. Dans un tel cas, le CGridView permet au développeur de définir une classe spécifique, dédié à la création du contenu d'une colonne, et ça, c'est plus que bien ! La classe CDataColumn (oui, c'est son nom), est utilisée par le CGridView, pour produire les chaînes de caractères qui viendront peupler ses colonnes. Cette classe accepte différents paramètres comme par exemple :

  • header : le titre de la colonne
  • footer : le pied de colonne
  • name : le nom de l'attribut associé à une colonne
  • type : pilote la façon dont le contenu de la colonne sera créé
  • value : une expression PHP dont l'évaluation sera interprétée comme le contenu de la colonne
  • etc ....
Nous avons déjà rencontré ces paramètres, et dans la plupart des cas, nous nous en accommoderons sans problème, mais pour ceux qui en veulent plus, ils ne sont pas suffisant. La solution consiste alors à définir notre propre classe, héritant de CDataColumn, puis d'indiquer au CGridView que c'est cette classe (la notre) qu'il devra utiliser plutôt que la classe de base CDataColumn.

Dans l'exemple suivant, nous avons donc créé notre propre classe afin de prendre en charge la création du contenu d'une colonne, dont le rôle est d'afficher une petite image d'enveloppe ouverte (pour les messages lus) ou fermée (pour les messages non lus) ... oui, il s'agit d'un exemple de boîte à lettres.

<?php
Yii::import('zii.widgets.grid.CDataColumn');

class MessageStatusColumn extends CDataColumn {

   // nous surchargons cette méthode qui est invoquée par le CGridView
   // chaque fois que le contenu d'une cellule doit être créé
   // L'argument $data représente l'instance affichée sur la ligne
   // correspondante.

   public function renderDataCellContent($row,$data)
   {
      $imgPath=Yii::app()->theme->baseUrl.'/images';

      // Bon, c'est juste un exemple, mais en gros le but est de générer
      // un tag image (IMG) en fonction de la valeur renvoyée par la
      // méthode hasBeenReadByUser() .. disponible au niveau du modèle
      // Message (le type de la variable $data)

      echo CHtml::image(
         $imgPath.'/'.($data->hasBeenReadByUser()?
            'email_read.png':
            'email_unread.png'),
         ($data->hasBeenReadByUser()?'':'*'),
         array(
            'title' => ($data->hasBeenReadByUser()?
               'message read':
               'message not read')
         )
      );
   }    
}
?>

D'autre méthodes de la classe CDataColum pourraient aussi être surchargées, mais pour les besoins de cet exemple, restons simples. Maintenant il ne reste plus qu'à déclarer notre CGridView, en précisant bien que c'est notre propre classe (MessageStatusColumn) qu'il convient d'utiliser pour l'affichage de la première colonne.

<?php 

$this->widget('zii.widgets.grid.CGridView', array(
   'id'=>'message-grid',
   'dataProvider'=>$model->search(),
   'columns'=>array(    
       array(
         
         // Ici on défini la classe à utiliser pour
         // afficher cette colonne
         
          'class'=> 'MessageStatusColumn',
          'name' => 'flags',
       ),
   // etc ...


Et le tour est joué !
Pour aller plus loin, les habituels liens :

lundi 13 juin 2011

formulaire : ajout de paramètre

Il peut arriver qu'un formulaire propose à l'utilisateur plusieurs boutons d'envoi, chacun ayant une signification différente. Par exemple un formulaire permettant pour l'écriture d'un message privé à destination d'un utilisateur, peut disposer d'un bouton 'envoyer' ainsi que d'un bouton 'sauvegarder'. Dans les deux cas, le formulaire pourra être traité par la même action, mais en fonction d'un paramètre additionnel, celle-ci procèdera uniquement à la sauvegarde du message (comme brouillon), ou bien sauvegardera puis enverra le message. La question est alors : comment rajouter ce paramètre ?
La solution proposée ici consiste à utiliser les paramètres de la méthode CHtml::submitButton() pour rajouter un paramètres GET à l'adresse d'envoi du formulaire. Ce paramètre (appellons-le 'envoi') a la valeur 1 ou 0 selon que l'on souhaite envoyer ou seulement sauvegarder (comme brouillon).

<div class="row buttons">
      <?php echo   
         CHtml::submitButton('Envoyer',array(
            // optionnel (pour le style)   
            'class' =>'button',
            // premier bouton : envoyer 
            // On utilise la paramètre 'submit' pour indiquer explicitement
            // l'adresse d'envoi du formulaire, et on en profite pour y
            // rajouter notre paramètre 'envoi=1'    
            'submit'=>$this->createUrl($this->route,array('envoi'=>1)),
         ));
      ?>         
      <?php echo 
         // second bouton : sauvegarder uniquement
         // Cette fois le paramètre 'envoi' est à 0
         CHtml::submitButton('Sauvegarder comme brouillon',array(
            'class' =>'button',
            // second bouton : sauvegarder uniquement
            // Cette fois le paramètre 'envoi' est à 0   
            'submit'=>$this->createUrl($this->route,array('envoi'=>0)),
         ));
      ?>     
   </div>


Côté contrôleur, c'est du classique : on rajoute le paramètres 'envoi' comme argument de l'action visée. Il sera automatiquement lié (bind) à la valeur de notre paramètre 'envoi'.
Bon, ça va pas chercher bien loin, mais ça peut toujours être utile ...
Pour aller plus loin :

lundi 30 mai 2011

CGridView : les colonnes à la une

Le composant CGridView (son nom complet est zii.widgets.grid.CGridView) fait partie des widgets de base du framework Yii. Il est utilisé notamment par Gii, le générateur de code intégré, lors de la création des fameux CRUD (Create, Read, Update, Delete). Si vous ne voyez toujours pas de qui je parle, allez faire un tour du côté de la démo Blog (pour vous connecter c'est demo/demo).
Ce joli tableau présente donc les valeurs des objets lus depuis la base de données par pages de 10 (défaut). Voyons un peu comment personnaliser le rendu des colonnes.
Pour cet exemple, nous allons nous baser sur une classe dérivée de CActiveRecord que nous appellerons MyRecord. Cette classe (hypothétique) comportera plusieurs attributs, qui devront apparaître dans chaque colonne du CGridView : 'id', 'name', 'create_time', etc ....

<?php $this->widget('zii.widgets.grid.CGridView', array(
   'id'=>'myrecord-grid',
   'dataProvider'  => $model->search(),
   'filter'        => $model,
   'columns'       => array(
      // 'id' et 'name' seront affichés normalement
      'id',
      'name',

      // Si MyRecord contient une relation nommée 'my_relation' et que l'objet 
      // en relation contient lui même un attribut nommé 'code', on peut
      // directement écrire :
      'my_relation.code'

      // 'create_time' est du type DATETIME : il sera affiché automatiquement
      // comme une date
      'create_time',

      // 'website_url' est ... une url ! il sera affiché en tant que lien
      // hypertexte
      array(
         'name' => 'website_url',
         'type' => 'url'
      ),

      // 'color' est une couleur (ex: #555343). Nous voulons l'utiliser pour
      // pour l'affichage de la valeur. Par exemple, la valeur 'red' sera 
      // affichée en rouge.
      array(
         'header' => 'Ma Couleur'   // nom de la colonne (entête)
         'name'   => 'color',       // nom de l'attribut
         'filter' => '',            // pas de filtre de colonne
         'type'   => 'raw',         // pas de conversion des caractères 
                                    // spéciaux
         'value'  => '"<span style=\"color:$data->color\">$data->color</span>"'     
      ),
      array(
         'class'=>'CButtonColumn',
      ),
   ),
)); ?>
Les valeurs disponibles pour le 'type' sont définies au niveau de la classe CFormatter


Modifier le nombre de lignes
Pour que votre CGridView affiche le nombre de ligne que vous souhaitez (par défaut : 10), il vous faudra intervenir au niveau du data provider. La ligne 03 affecte le data provider renvoyé par la méthode search(), à votre grid. C'est donc dans la méthode search() que nous allons changer les paramètres d'initialisation du data provider.

return new CActiveDataProvider(get_class($this), array(
         'criteria'=>$criteria,
          'pagination'=>array(
              // on va choisir d'afficher 20 lignes par page
              'pageSize'=>20,
          ),
      ));

Notons que le data provider prend en charge tout ce qui concerne la pagination

Voilà pour un premier aperçu de cette widget standard Yii. Il y a encore beaucoup à dire sur le sujet et les possibilités de personnalisation sont légions. Ce sera l'objet d'un prochain post (peut-être).
Pour aller plus loin, voici quelques liens utiles :