Pagination de checkbox complétée depuis la BDD sous codeigniter

Pagination de checkbox complétée depuis la BDD sous codeigniter

Je fais une petite fixette sur codeigniter dans le cadre de l’écriture d’une application en ce moment. Ce billet est un aide mémoire (ou un tuto de bout en bout pour ceux que ça intéresse).

Contexte :

L’application a comme groupes de rôles l’administrateur puis quelques milliers d’autres groupes destinés à restreindre en visibilité les utilisateurs (environ 10000) dès la connexion sur leurs groupes utilisateurs respectifs. Pour schématiser, c’est un peu le fonctionnement de consultation de N comptes bancaires qui seraient consultés chacun par X utilisateurs.

Problème :

Pour initier le projet, j’ai pris le parti de ne pas me casser la tête à créer la librairie d’authentification de toute pièce. Mon choix s’est donc porté sur Codeigniter ion_auth library qui est complète et simple d’utilisation MAIS qui présente un très gros inconvénient : il n’y a pas de système de pagination des groupes utilisateurs.
Dans son fonctionnement, la librairie ion auth propose d’assigner les groupes aux utilisateurs (ce qui m’arrangeait). C’est pratique quand on a 4 ou 5 rôles à distribuer mais avec plus de 3000 rôles (correspondant à des groupes de consultation), ça devient totalement ingérable. Il est impensable de devoir chercher, depuis une fiche utilisateur, quelles sont les cases à cocher parmi 3000 groupes portant approximativement le même nom.

Solution :

Pour résoudre ce désagrément sans tout exploser, j’ai sorti le combo JSON + jQuery + datatables pour résoudre ce problème de pagination de checkboxes en utilisant ce que j’ai trouvé sur internet. Le moteur de recherche m’a guidé vers :

C’est parti !

Etape 1 : Création du fichier JSON

Ce fichier est utilisé par le script de génération des groupes. Il est utilisé pour afficher l’intégralité des groupes utilisateurs de ion auth sur lesquels ont va jouer avec les cases à cocher.

Il est formé de cette manière :
{« data »:[[« 1″, »admin »],[« 2″, »members »],[« 6″, »GROUPE1 »],[« 7″, »GROUPE2 »],[« 8″, »GROUPE3 »]]}

Comme ce n’est pas la construction par défaut de ce que ion auth propose pour la création de notre json sous codeigniter, on va exploiter une méthode du modèle Ion_auth_model.php

$this->data['groups'] = $this->ion_auth->groups()->result();

// CREATION DU JSON
$longueur = count($this->data['groups']);
$contenu_json = '{"data":[';
for ($i=0; $i < $longueur; $i++)
{
  $contenu_json .= '["'.$this->data['groups'][$i]->id.'","'.$this->data['groups'][$i]->name.'"]';
  if ($i != $longueur-1)
  {
    $contenu_json .= ',';
  }
}
$contenu_json .= ']}';
// FIN CREATION JSON

    //echo '{"data":[["'.$this->data['groups'][0]->id.'","'.$this->data['groups'][0]->name.'"]]}';
//$contenu_json = json_encode($this->data['groups']);
//var_dump($contenu_json);

// Nom du fichier à créer
$nom_du_fichier = 'fichier.json';

// Ouverture du fichier
$fichier = fopen($nom_du_fichier, 'w+');

// Ecriture dans le fichier
fwrite($fichier, $contenu_json);

// Fermeture du fichier
fclose($fichier);

C’est fait. Notre fichier fichier.json est dorénavant à la racine -> http://localhost/fichier.json (qu’il faudra placer ailleurs en situation réelle, bien sûr).

On peut du coup passer à la suite.

Etape n°2 : Préparation du tableau de cases à cocher datatables

Dans la vue users/edit_user_view.php virer

  <div class="form-group">
    <?php
    if(isset($groups))
    {
      echo form_label('Groupes','groups[]');
      foreach($groups as $group)
      {
        echo '<div class="checkbox">';
        echo '<label>';
        echo form_checkbox('groups[]', $group->id, set_checkbox('groups[]', $group->id, in_array($group->id,$usergroups)));
        echo ' '.$group->name;
        echo '</label>';
        echo '</div>';
      }
    }
    ?>
  </div>
  <?php echo form_hidden('user_id',$user->id);?>
  <?php echo form_submit('submit', 'Modifier l\'utilisateur', 'class="btn btn-primary btn-lg btn-block"');?>
<?php echo form_close();?>

et remplacer par  :

<div class="form-group">
<table id="example" class="display select" cellspacing="0" width="100%">
   <thead>
      <tr>
         <th><input name="select_all" value="1" type="checkbox"></th>
         <th>Noms Groupes</th>
      </tr>
   </thead>
</table>
<?php echo form_hidden('user_id',$user->id);?>
<p><button class="btn btn-primary btn-lg btn-block">Modifier les données</button></p>
</form>

L’absence de balise <td></td> est normale. Elle vont apparaître à la lecture du JSON.

Etape 3 : JQuery de génération des cases à cocher datatables, coche des cases de la BDD et soumission du formulaire

a/ Traiter le contrôleur pour que la vue repeuple le formulaire des cases déjà cochées (en base)

Dans Users.php qui envoie les données à la vue, il faut charger $this->data['votrevariable'] avec les groupes déjà assignés à l’utilisateur pour recocher les cases :

$this->data['groupes_utilisateur'] = $usergroups = $this->ion_auth->get_users_groups($user->id)->result();

b/ Positionner le script Jquery de génération / lecture des cases à cocher

Et $groupes_utilisateur est exploité par le javascript (cf. ci-dessous « boucle de récupération des groupes ») :

<script type="text/javascript">
// DEBUT SCRIPT JSON
function updateDataTableSelectAllCtrl(table){
   var $table             = table.table().node();
   var $chkbox_all        = $('tbody input[type="checkbox"]', $table);
   var $chkbox_checked    = $('tbody input[type="checkbox"]:checked', $table);
   var chkbox_select_all  = $('thead input[name="select_all"]', $table).get(0);

   // Si aucune des checkbox n'est cochée
   if($chkbox_checked.length === 0){
      chkbox_select_all.checked = false;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = false;
      }

   // Si toutes les checkbox sont cochées
   } else if ($chkbox_checked.length === $chkbox_all.length){
      chkbox_select_all.checked = true;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = false;
      }

   // Si quelques checkbox sont cochées
   } else {
      chkbox_select_all.checked = true;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = true;
      }
   }
}

$(document).ready(function (){
   
   <?php 
   // boucle de récupération des groupes de l'utilisateur pour 
   // repeupler le tableau
   $lignes_a_cocher = "";
   foreach ($groupes_utilisateur as $guser) {
      $lignes_a_cocher .= '"'.$guser->id.'",';
   } 
   $lignes_a_cocher = rtrim($lignes_a_cocher,',');


   ?>
   // Tableau contenant les ID sélectionnés
   var rows_selected = [<?php echo $lignes_a_cocher?>];
   var table = $('#example').DataTable({
      'ajax': 'http://localhost/fichier.json',
      'columnDefs': [{
         'targets': 0,
         'searchable':false,
         'orderable':false,
         'width':'1%',
         'className': 'dt-body-center',
         'render': function (data, type, full, meta){
             return '<input type="checkbox">';
         }
      }],
      'order': [1, 'asc'],
      'rowCallback': function(row, data, dataIndex){
         // Récupération du row ID
         var rowId = data[0];

         // SI le row ID est dans la liste des row ID sélectionnés
         if($.inArray(rowId, rows_selected) !== -1){
            $(row).find('input[type="checkbox"]').prop('checked', true);
            $(row).addClass('selected');
         }
      }
   });

   // Tient le clic sur la checkbox
   $('#example tbody').on('click', 'input[type="checkbox"]', function(e){
      var $row = $(this).closest('tr');

      // Récupère le row data
      var data = table.row($row).data();

      // Récupère le row ID
      var rowId = data[0];

      // Determine whether row ID is in the list of selected row IDs 
      var index = $.inArray(rowId, rows_selected);

      // Si la checkbox est cochée et que le row ID n'est pas
      // dans la liste des row ID
      if(this.checked && index === -1){
         rows_selected.push(rowId);

      // Sinon, si la checkbox n'est pas cochée et 
      // que le rowID est dans la liste des row ID sélectionnés
      } else if (!this.checked && index !== -1){
         rows_selected.splice(index, 1);
      }

      if(this.checked){
         $row.addClass('selected');
      } else {
         $row.removeClass('selected');
      }

      // Met à jour le contrôle SELECT ALL
      updateDataTableSelectAllCtrl(table);

      // Evite que le clic se propage au parent
      e.stopPropagation();
   });

   // Gère le clic sur les cellules en lien avec les checkboxes
   $('#example').on('click', 'tbody td, thead th:first-child', function(e){
      $(this).parent().find('input[type="checkbox"]').trigger('click');
   });

   // Gère le clic select all
   $('thead input[name="select_all"]', table.table().container()).on('click', function(e){
      if(this.checked){
         $('#example tbody input[type="checkbox"]:not(:checked)').trigger('click');
      } else {
         $('#example tbody input[type="checkbox"]:checked').trigger('click');
      }

      // Evite que le clic se propage au parent
      e.stopPropagation();
   });

   // Récupère les évènements du draw de la table
   table.on('draw', function(){
      // Mets à jour en cas de "select all"
      updateDataTableSelectAllCtrl(table);
   });
    
   // Récupère l'évènement de soumission de formulaire 
    $('#frm-example').submit(function(e) {
      var form = this;

      // Itère en fonction des checkboxes cochées
      $.each(rows_selected, function(index, rowId){
         // Constitution du formulaire
         $(form).append(
             $('<input>')
                .attr('type', 'hidden')
                .attr('name', 'groups[]')
                .val(rowId)
         );
      });

   });
});
// FIN SCRIPT JSON

Youhou ! Ca marche !

 

PS : A ajouter dans le header (en plus de jquery)

<script src="https://cdn.datatables.net/select/1.2.7/js/dataTables.select.min.js"></script>
<link type="text/css" href="https://cdn.datatables.net/select/1.2.7/css/select.dataTables.min.css" rel="stylesheet" >

 

 

Laisser un commentaire