Connexion S'inscrire

Connectez-vous

Login *
Mot de passe *
Se souvenir de moi

Créer un compte

Les champs marqués d'un astérisque (*) sont requis.
Nom *
Login *
Mot de passe *
Vérification mot de passe *
Email *
Vérification email *
Captcha *

Création d'un composant Joomla (partie 21) Ordonner - Trier par - Recherche


Dans cette partie,  nous allons rajouter la possibilité d'ordonner la liste, de trier ou de faire des recherches dans la vue liste en administration. Tout se passera côté administrateur donc dans le dossier administrator. Si vous êtes arrivés directement sur cette page, peut-être que vous aimeriez commencer par le début: Partie 1 | Partie 2 | Partie 3 | Partie 4 | Partie 5 | Partie 6 | Partie 7 | Partie 8 | Partie 9 | Partie 10 | Partie 11 | Partie 12 | Partie 13 | Partie 14 | Partie 15 | Partie 16 | Partie 17 | Partie 18 | Partie 19 | Partie 20

1 - Introduction

Nous allons utiliser le champ ordering pour permettre à l'administrateur d'ordonner les éléments comme il le désir. Plus tard, nous ferons des modifications au côté client pour que les éléments soient affichés en respectant cet ordre.

 

2 - Formulaire de recherche et de tri

Nous allons créer un deuxième formulaire qui permettra de faire des recherches dans la liste, d'ordonner la liste par nom, date de création... Dans le dossier models/forms, nous allons créer un nouveau fichier XML nommé filter_guitaristes.xml. Voici le contenu de ce formulaire :

<?xml version="1.0" encoding="utf-8"?>
<form>
  <fields name="filter">
      <field name="search" type="text" hint="COM_DJGUITARISTE_SEARCH_FILTER_SUBMIT"
         label="COM_DJGUITARISTE_FILTER_SEARCH_DESC"
         class="js-stools-search-string" />

      <field
        name="category_id"
        type="category"
        label="JOPTION_FILTER_CATEGORY"
        description="JOPTION_FILTER_CATEGORY_DESC"
        multiple="true"
        class="multipleCategories"
        extension="com_djguitariste"
        onchange="this.form.submit();"
        published="0,1,2"
    />
  </fields>

  <fields name="list">
    <field
      name="fullordering"
      type="list"
      label="COM_CONTENT_LIST_FULL_ORDERING"
      description="COM_CONTENT_LIST_FULL_ORDERING_DESC"
      onchange="this.form.submit();"
      default="a.id DESC"
      >
      <option value="">JGLOBAL_SORT_BY</option>
      <option value="a.ordering ASC">JGRID_HEADING_ORDERING_ASC</option>
      <option value="a.ordering DESC">JGRID_HEADING_ORDERING_DESC</option>
      <option value="a.state ASC">JSTATUS_ASC</option>
      <option value="a.state DESC">JSTATUS_DESC</option>
      <option value="a.name ASC">COM_DJGUITARISTE_NAME_ASC</option>
      <option value="a.name DESC">COM_DJGUITARISTE_NAME_DESC</option>
      <option value="a.created ASC">JDATE_ASC</option>
      <option value="a.created DESC">JDATE_DESC</option>
      <option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
      <option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
    </field>

    <field
      name="limit"
      type="limitbox"
      label="COM_CONTENT_LIST_LIMIT"
      description="COM_CONTENT_LIST_LIMIT_DESC"
      class="input-mini"
      default="20"
      onchange="this.form.submit();"
    />
  </fields>

</form>

Ce formulaire comprend deux groupes d'éléments entre des balises fields. Le premier affiche un champ de recherche et un champs pour sélectionner les catégories. Le deuxième Affiche une liste pour sélectionner la façon dont on veut trier les données et une liste pour sélectionner le nombre d'éléments à afficher sur la page. La propriété onChange permet de définir le comportement à adopter à chaque fois qu'un élément est changé dans la liste. Dans notre cas, on soumet le formulaire donc la page est recharger.

 

3 - Modification du modèle (guitaristes.php)

Nous allons redéfinir un constructeur dans notre modèle. Ce constructeur va définir dans un tableau, la liste des champs qui seront utilisés pour filtrer les données. Ensuite nous appelons le constructeur de la classe parent en lui passant le tableau en paramètre:

public function __construct($config = array())
  {
    if (empty($config['filter_fields']))
    {
      $config['filter_fields'] = array(
        'id', 'a.id',
        'name', 'a.name',
        'alias', 'a.alias',
        'checked_out', 'a.checked_out',
        'checked_out_time', 'a.checked_out_time',
        'catid', 'a.catid', 'category',
        'state', 'a.state',
        'created', 'a.created',
        'modified', 'a.modified',
        'created_by', 'a.created_by',
        'created_by_alias', 'a.created_by_alias',
        'ordering', 'a.ordering',
        'publish_up', 'a.publish_up',
        'publish_down', 'a.publish_down',
        'category_id'
      );
    }

    parent::__construct($config);
  }

Nous allons aussi rajouter la méthode  populateState():

protected function populateState($ordering = 'a.ordering', $direction = 'asc')
  {
    // Initialise variables.
    $app = JFactory::getApplication('administrator');

    // Load the filter state.
    $search = $app->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
    $this->setState('filter.search', $search);

    $published = $app->getUserStateFromRequest($this->context . '.filter.state', 'filter_published', '', 'string');
    $this->setState('filter.state', $published);

    // Load the parameters.
    $params = JComponentHelper::getParams('com_djguitariste');
    $this->setState('params', $params);

    // List state information.
    parent::populateState($ordering, $direction);
  }

 

Si vous avez suivis le tutoriel précédent vous devez avoir "a.ordering" dans la liste des éléments sélectionnés dans la méthode getListQuery(). Dans cette méthode, nous tenons compte des informations qui viennent du formulaire pour filtrer les données.

public function getListQuery()
{
	$db = $this->getDbo();
	$query = $db->getQuery(true);
	$query->select('a.id, a.name, a.state, a.publish_up, a.publish_down, a.catid, a.created, a.created_by, a.ordering, a.checked_out, a.checked_out_time');
	$query->from($db->quoteName('#__djguitariste_items').' AS a');

	// Join over the users for the checked out user.
	$query->select('uc.name AS editor')
	  ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out');

	$query->select('c.title AS category');
	$query->join('LEFT', $db->quoteName('#__categories').' AS c ON c.id = a.catid');

	$query->order($db->escape($this->getState('list.ordering', 'a.id')).' '.
	$db->escape($this->getState('list.direction', 'DESC')));


	// Filter by search in title.
	$search = $this->getState('filter.search');
	$state  = $this->getState('filter.state');
	 
	if (!empty($search))
	{     
	  $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'));
	  $query->where('(a.name LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')');      
	}

	// Filter by a single or group of categories.
	$baselevel  = 1;
	$categoryId = $this->getState('filter.category_id');

	if (is_numeric($categoryId))
	{
	  $categoryTable = JTable::getInstance('Category', 'JTable');
	  $categoryTable->load($categoryId);
	  $rgt       = $categoryTable->rgt;
	  $lft       = $categoryTable->lft;
	  $baselevel = (int) $categoryTable->level;
	  $query->where('c.lft >= ' . (int) $lft)
		->where('c.rgt <= ' . (int) $rgt);
	}
	elseif (is_array($categoryId))
	{
	  $categoryId = ArrayHelper::toInteger($categoryId);
	  $query->where('a.catid IN (' . implode(',', ArrayHelper::toInteger($categoryId)) . ')');
	}

	return $query;
}

Le contenu du modèle au complet devrait ressembler à ceci:


<?php
defined('_JEXEC') or die;

use Joomla\Utilities\ArrayHelper;

class DJGuitaristeModelGuitaristes extends JModelList
{
  
  public function __construct($config = array())
  {
    if (empty($config['filter_fields']))
    {
      $config['filter_fields'] = array(
        'id', 'a.id',
        'name', 'a.name',
        'alias', 'a.alias',
        'checked_out', 'a.checked_out',
        'checked_out_time', 'a.checked_out_time',
        'catid', 'a.catid', 'category',
        'state', 'a.state',
        'created', 'a.created',
        'modified', 'a.modified',
        'created_by', 'a.created_by',
        'created_by_alias', 'a.created_by_alias',
        'ordering', 'a.ordering',
        'publish_up', 'a.publish_up',
        'publish_down', 'a.publish_down',
        'category_id'
      );
    }

    parent::__construct($config);
  }
  
  
    /**
   * Method to auto-populate the model state.
   *
   * Note. Calling getState in this method will result in recursion.
   *
   * @param   string  $ordering   Elements order
   * @param   string  $direction  Order direction
   *
   * @return void
   *
   * @throws Exception
   */
  protected function populateState($ordering = 'a.ordering', $direction = 'asc')
  {
    // Initialise variables.
    $app = JFactory::getApplication('administrator');

    // Load the filter state.
    $search = $app->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
    $this->setState('filter.search', $search);

    $published = $app->getUserStateFromRequest($this->context . '.filter.state', 'filter_published', '', 'string');
    $this->setState('filter.state', $published);

    // Load the parameters.
    $params = JComponentHelper::getParams('com_djguitariste');
    $this->setState('params', $params);

    // List state information.
    parent::populateState($ordering, $direction);
  }
  
  public function getListQuery()
  {
    $db = $this->getDbo();
    $query = $db->getQuery(true);
    $query->select('a.id, a.name, a.state, a.publish_up, a.publish_down, a.catid, a.created, a.created_by, a.ordering, a.checked_out, a.checked_out_time');
    $query->from($db->quoteName('#__djguitariste_items').' AS a');
    
    // Join over the users for the checked out user.
    $query->select('uc.name AS editor')
      ->join('LEFT', '#__users AS uc ON uc.id=a.checked_out');
    
    $query->select('c.title AS category');
    $query->join('LEFT', $db->quoteName('#__categories').' AS c ON c.id = a.catid');
    
    $query->order($db->escape($this->getState('list.ordering', 'a.id')).' '.
    $db->escape($this->getState('list.direction', 'DESC')));
    
    
    // Filter by search in title.
    $search = $this->getState('filter.search');
    $state  = $this->getState('filter.state');
     
    if (!empty($search))
    {     
      $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'));
      $query->where('(a.name LIKE ' . $search . ' OR a.alias LIKE ' . $search . ')');      
    }
    
    // Filter by a single or group of categories.
    $baselevel  = 1;
    $categoryId = $this->getState('filter.category_id');

    if (is_numeric($categoryId))
    {
      $categoryTable = JTable::getInstance('Category', 'JTable');
      $categoryTable->load($categoryId);
      $rgt       = $categoryTable->rgt;
      $lft       = $categoryTable->lft;
      $baselevel = (int) $categoryTable->level;
      $query->where('c.lft >= ' . (int) $lft)
        ->where('c.rgt <= ' . (int) $rgt);
    }
    elseif (is_array($categoryId))
    {
      $categoryId = ArrayHelper::toInteger($categoryId);
      $query->where('a.catid IN (' . implode(',', ArrayHelper::toInteger($categoryId)) . ')');
    }
    
    return $query;
  }
  
}

4 - La vue

4.1 - Le fichier view.html.php

Dans la fonction display(), nous apportons les modifications suivante pour créer le formulaire de filtrage, récupérer les information déjà soumis dans ce formulaire si l'administrateur a sélectionné quelque chose précédemment. Voici la méthode après la modification.

public function display($tpl = null)
{
	$items = $this->get('Items');
	$this->items = &$items;
        
	$state = $this->get('State');
	$this->state = &$state;

	$this->filterForm = $this->get('FilterForm');

	$this->sortDirection = $state->get('list.direction');
	$this->sortColumn = $state->get('list.ordering');
        
	$pagination = $this->get('Pagination');
	$this->pagination = $pagination;

	DJGuitaristeHelper::addSubmenu('guitaristes');
	$this->sidebar = JHtmlSidebar::render();

	//Appel de la fonction pour créer la barre d'outil
	$this->addToolbar();

	parent::display($tpl);
}

 

4.2 Le layout default.php

Nous commençons par importer des librairies JavaScript pour le bon fonctionnement de notre formulaire. D'habitude l'import se place en haut juste après la condition defined()...

JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', '.multipleCategories', null, array('placeholder_text_multiple' => JText::_('JOPTION_SELECT_CATEGORY')));
JHtml::_('formbehavior.chosen', 'select');

Puis nous prenons les informations de l'utilisateur en cours pour décider du comportement de certains éléments de la page en fonction des droits d'accès de cet utilisateur. Nous allons aussi chercher à savoir comment sont ordonnées les éléments ainsi que la direction (ascendant ou descendant) dans laquelle ils sont ordonnés.

$user      = JFactory::getUser();
$userId    = $user->get('id');
$listOrder = $this->state->get('list.ordering');
$listDirn  = $this->state->get('list.direction');
$canOrder  = $user->authorise('core.edit.state', 'com_djguitariste');
$saveOrder = $listOrder == 'a.ordering';

if ($saveOrder)
{
  $saveOrderingUrl = 'index.php?option=com_djguitariste&task=guitaristes.saveOrderAjax&tmpl=component';
  JHtml::_('sortablelist.sortable', 'guitaristes', 'adminForm', strtolower($listDirn), $saveOrderingUrl);
}

Avant le tableau, nous affichons le formulaire de tri et de recherche grâce à cette ligne:

<?php echo JLayoutHelper::render('joomla.searchtools.default', array('view' => $this));  ?>

Dans la section thead du tableau, nous rajoutons ordering au début du tableau et nous passons par la classe JHtml pour afficher tous les titres et permettre de trier les éléments du tableau en cliquant sur le titre d'une colonne.

<thead>
	<tr>
	  <th width="1%" class="nowrap center hidden-phone">
		<?php echo JHtml::_('searchtools.sort', '', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-menu-2'); ?>
	  </th>
	  <th width="1%">
		<input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)" />
	  </th>
	  <th width="1%" style="min-width:55px;" class="nowrap center">
		<?php echo JHtml::_('searchtools.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
	  </th>
	  <th class="title">
		<?php echo JHtml::_('searchtools.sort', 'COM_DJGUITARISTE_NAME', 'a.name', $listDirn, $listOrder); ?>            
	  </th>
	  <th width="15%" class="nowrap hidden-phone">
		<?php echo JHtml::_('searchtools.sort', 'COM_DJGUITARISTE_CREATED', 'a.created', $listDirn, $listOrder); ?>
	  </th>
	  <th width="1%" class="nowrap center">
		<?php echo JHtml::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
	  </th>
	</tr>
</thead>

Dans la section tbody juste au début de la boucle foreach(), nous vérifions le droit de l'utilisateur sur chacun des éléments.

$canEdit    = $user->authorise('core.edit',       'com_djguitariste.category.' . $item->catid);
$canCreate  = $user->authorise('core.create',     'com_djguitariste');   
$canCheckin = $user->authorise('core.manage',     'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0;
$canEditOwn = $user->authorise('core.edit.own',   'com_djguitariste.category.' . $item->catid) && $item->created_by == $userId;
$canChange  = $user->authorise('core.edit.state', 'com_djguitariste.category.' . $item->catid) && $canCheckin;

Nous ajoutons le tout premier td qui permettra d'ordonner les éléments.

<td class="order nowrap center hidden-phone">
	<?php if ($canChange) :
	  $disableClassName = '';
	  $disabledLabel    = '';

	  if (!$saveOrder) :
		$disabledLabel    = JText::_('JORDERINGDISABLED');
		$disableClassName = 'inactive tip-top';
	  endif; ?>
	  <span class="sortable-handler hasTooltip <?php echo $disableClassName ?>"
		  title="<?php echo $disabledLabel ?>">
		  <i class="icon-menu"></i>
		</span>
	  <input type="text" style="display:none" name="order[]" size="5"
		   value="<?php echo $item->ordering; ?>" class="width-20 text-area-order "/>
	<?php else : ?>
	  <span class="sortable-handler inactive">
	  <i class="icon-menu"></i>
	</span>
	<?php endif; ?>
</td>

Dans le td qui contient l'affichage du nom du guitariste, on va maintenant vérifier les droits de l'utilisateur afin de décider si on affiche le lien d'édition ou pas.

<td class="nowrap">
	<?php 
	if ($item->checked_out) :?>
		  <?php echo JHtml::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'guitaristes.', $canCheckin); ?>
	<?php endif; ?>
	<?php if ($canEdit || $canEditOwn) : ?>
	  <a href="/<?php echo JRoute::_('index.php?option=com_djguitariste&task=guitariste.edit&layout=edit&id='.(int)$item->id); ?>">
		<?php echo $item->name; ?>
	  </a>
	<?php else: ?>
	  <?php echo $item->name; ?>
	<?php endif; ?>
	<p class="small">
	  <?php echo $this->escape($item->category); ?>
	</p>
</td>

Tout le contenu du fichier devrait ressembler à ceci :

<?php
defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', '.multipleCategories', null, array('placeholder_text_multiple' => JText::_('JOPTION_SELECT_CATEGORY')));
JHtml::_('formbehavior.chosen', 'select');


$user      = JFactory::getUser();
$userId    = $user->get('id');
$listOrder = $this->state->get('list.ordering');
$listDirn  = $this->state->get('list.direction');
$canOrder  = $user->authorise('core.edit.state', 'com_djguitariste');
$saveOrder = $listOrder == 'a.ordering';

if ($saveOrder)
{
  $saveOrderingUrl = 'index.php?option=com_djguitariste&task=guitaristes.saveOrderAjax&tmpl=component';
  JHtml::_('sortablelist.sortable', 'guitaristes', 'adminForm', strtolower($listDirn), $saveOrderingUrl);
}

?>

<form action="<?php echo JRoute::_('index.php?option=com_djguitariste&view=guitaristes'); ?>" method="post" name="adminForm" id="adminForm">

  <?php if(!empty($this->sidebar)): ?>
    <div id="j-sidebar-container" class="span2">
      <?php echo $this->sidebar; ?>
    </div>
    <div id="j-admin-container" class="span10 j-toggle-main" style="float:right;">
  <?php else: ?>
    <div id="j-admin-container">
  <?php endif; ?>
    <?php echo JLayoutHelper::render('joomla.searchtools.default', array('view' => $this));  ?>
    
    <table class="table table-striped" id="guitaristes">
      <thead>
        <tr>
          <th width="1%" class="nowrap center hidden-phone">
            <?php echo JHtml::_('searchtools.sort', '', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-menu-2'); ?>
          </th>
          <th width="1%">
            <input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)" />
          </th>
          <th width="1%" style="min-width:55px;" class="nowrap center">
            <?php echo JHtml::_('searchtools.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
          </th>
          <th class="title">
            <?php echo JHtml::_('searchtools.sort', 'COM_DJGUITARISTE_NAME', 'a.name', $listDirn, $listOrder); ?>            
          </th>
          <th width="15%" class="nowrap hidden-phone">
            <?php echo JHtml::_('searchtools.sort', 'COM_DJGUITARISTE_CREATED', 'a.created', $listDirn, $listOrder); ?>
          </th>
          <th width="1%" class="nowrap center">
            <?php echo JHtml::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
          </th>
        </tr>
      </thead>
      <tfoot>
        <tr>
          <td colspan="6">
            <?php echo $this->pagination->getListFooter(); ?>
          </td>
        </tr>
      </tfoot>
      <tbody>
      <?php foreach($this->items as $i => $item){
        $canEdit    = $user->authorise('core.edit',       'com_djguitariste.category.' . $item->catid);
        $canCreate  = $user->authorise('core.create',     'com_djguitariste');   
        $canCheckin = $user->authorise('core.manage',     'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0;
        $canEditOwn = $user->authorise('core.edit.own',   'com_djguitariste.category.' . $item->catid) && $item->created_by == $userId;
        $canChange  = $user->authorise('core.edit.state', 'com_djguitariste.category.' . $item->catid) && $canCheckin;
        ?>
        <tr class="row<?php echo $i % 2; ?>">
          <td class="order nowrap center hidden-phone">
                <?php if ($canChange) :
                  $disableClassName = '';
                  $disabledLabel    = '';

                  if (!$saveOrder) :
                    $disabledLabel    = JText::_('JORDERINGDISABLED');
                    $disableClassName = 'inactive tip-top';
                  endif; ?>
                  <span class="sortable-handler hasTooltip <?php echo $disableClassName ?>"
                      title="<?php echo $disabledLabel ?>">
              <i class="icon-menu"></i>
            </span>
                  <input type="text" style="display:none" name="order[]" size="5"
                       value="<?php echo $item->ordering; ?>" class="width-20 text-area-order "/>
                <?php else : ?>
                  <span class="sortable-handler inactive">
              <i class="icon-menu"></i>
            </span>
                <?php endif; ?>
          </td>
          <td class="center">
            <?php echo JHtml::_('grid.id', $i, $item->id); ?>
          </td>
          <td class="center">
            <?php echo JHtml::_('jgrid.published', $item->state, $i, 'guitaristes.', true, 'cb', $item->publish_up, $item->publish_down); ?>
          </td>
          <td class="nowrap">
            <?php 
            if ($item->checked_out) :?>
                  <?php echo JHtml::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'guitaristes.', $canCheckin); ?>
            <?php endif; ?>
            <?php if ($canEdit || $canEditOwn) : ?>
              <a href="/<?php echo JRoute::_('index.php?option=com_djguitariste&task=guitariste.edit&layout=edit&id='.(int)$item->id); ?>">
                <?php echo $item->name; ?>
              </a>
            <?php else: ?>
              <?php echo $item->name; ?>
            <?php endif; ?>
            <p class="small">
              <?php echo $this->escape($item->category); ?>
            </p>
          </td>
          <td class="nowrap"><?php echo JHtml::_('date', $this->escape($item->created), JText::_('DATE_FORMAT_LC4')); ?></td>
          <td class="center">
            <?php echo $item->id; ?>
          </td>
        </tr>
      <?php } ?>
      </tbody>
    </table>
    <input type="hidden" name="task" value="" />
    <input type="hidden" name="boxchecked" value="0" />
    <input type="hidden" name="view" value="guitaristes" />
    <?php echo JHtml::_('form.token'); ?>
  </div>
</form> 

 

Voilà maintenant la page liste devrait ressembler à ceci:

 

 

Si vous avez des questions, veuillez utiliser le formulaire de contact ou notre page Facebook.

Lire la suite...


  • Dernière modification le jeudi, 26 octobre 2017 01:16
  • 341
Docteur Joomla

Après plus de 10 ans d'expérience en Joomla, je lance ce Blog pour partager mes connaissances avec les autres développeurs Joomla.