Développement d'un composant MVC - Ajout de filtres
From Joomla! Documentation
Les articles de cette série
Ajout d'un type de menu à la partie site
Ajout d'un modèle à la partie site
Ajout d'une requête de variable dans le type de menu
Utilisation de la base de données
Backend de base
Ajout de la gestion des langues
Ajout d'actions en backend
Ajout de décorations pour le backend
Ajout de vérifications
Ajout de catégories
Ajout de configuration
Ajout d'un fichier script installation/désinstallation/mise à jour
Ajout d'un formulaire de frontend
Utilisation du filtre de langues
- Ajouter une fenêtre modale
- Ajout d'associations
- Ajout de Checkout
- Ajout d'un filtre
- Ajout de niveaux
- Ajout de versions
- Ajout de tags
- Ajout d'accès
- Ajout d'un processus de traitement
- Ajout d'un cache
- Ajout d'un fil d'actualité
Ajout d'un serveur de mise à jour
Ceci est une série qui regroupe plusieurs articles pour devenir un didacticiel sur la façon de développer un Composant pour Joomla!
suivant le principe Modèle-Vue-Contrôleur.
Commencez avec l'introduction, et naviguez dans les articles de cette série soit à l'aide des boutons de navigation en bas des articles, soit grâce au menu de droite : Les articles de cette série.
This tutorial is part of the Developing an MVC Component for Joomla! 3.2 tutorial. You are encouraged to read the previous parts of the tutorial before reading this.
In this step we add ordering capability to our component.
A video accompanying this step can be found at Adding Ordering.
Introduction
Joomla core components allow the administrator to define an arbitrary ordering of items by clicking on the Ordering symbol (a little up arrowhead above a down arrowhead) at the top left of the items table, and then clicking on one of the 3 vertical dots symbols and sliding the record up or down to reorder.
In this step we build the code to support this functionality for Helloworld records. Like Joomla core components we'll allow the administrator to specify the order within a category, although this can be easily changed to allow ordering across a different set of records (eg ordering within a language), or across all helloworld records.
We'll use the order defined by the administrator when we output the Category view of helloworld records on the front end.
Approche
We need to store the Ordering in the database, and we'll follow the example of Joomla components and call this field "Ordering". As usual, naming a field in a way that aligns with Joomla core unlocks a lot of library functionality which we can reuse.
Our main work in the back end is associated with the helloworlds view
- including the Ordering field within our query
- including the Ordering field within our filter fields, as we'll want to sort the table using that field
- displaying the Ordering column in the layout file, and setting up the data to enable the dynamic reording functionality (ie sliding the record up/down to reorder).
- because we're going to allow ordering within a category, we'll include the category within the filter fields.
On the front end category view we'll set up the default ordering to use the Ordering field from the database.
We also have to consider what the Ordering field should be set to whenever new helloworld records are created, remembering that this can occur on both the back end and the front end. In both these cases we can set the value of Ordering within a function prepareTable($table) which Joomla will call prior to saving the record in the database. We put this function into the appropriate model: admin/models/helloworld.php for the back end and site/models/form.php for the front end.
Updating the Database
Add the ordering field to the database record:
admin/sql/install.mysql.utf8.sql
DROP TABLE IF EXISTS `#__helloworld`;
CREATE TABLE `#__helloworld` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`asset_id` INT(10) NOT NULL DEFAULT '0',
`created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`checked_out` INT(10) NOT NULL DEFAULT '0',
`checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`greeting` VARCHAR(25) NOT NULL,
`alias` VARCHAR(40) NOT NULL DEFAULT '',
`language` CHAR(7) NOT NULL DEFAULT '*',
`ordering` int(11) NOT NULL DEFAULT '0',
`published` tinyint(4) NOT NULL DEFAULT '1',
`catid` int(11) NOT NULL DEFAULT '0',
`params` VARCHAR(1024) NOT NULL DEFAULT '',
`image` VARCHAR(1024) NOT NULL DEFAULT '',
`latitude` DECIMAL(9,7) NOT NULL DEFAULT 0.0,
`longitude` DECIMAL(10,7) NOT NULL DEFAULT 0.0,
PRIMARY KEY (`id`)
)
ENGINE =MyISAM
AUTO_INCREMENT =0
DEFAULT CHARSET =utf8;
CREATE UNIQUE INDEX `aliasindex` ON `#__helloworld` (`alias`, `catid`);
INSERT INTO `#__helloworld` (`greeting`,`alias`,`language`,`ordering`) VALUES
('Hello World!','hello-world','en-GB',1),
('Goodbye World!','goodbye-world','en-GB',2);
New SQL update file:
/admin/sql/updates/mysql/0.0.25.sql
ALTER TABLE`#__helloworld` ADD COLUMN `ordering` int(11) NOT NULL DEFAULT '0' AFTER `language`;
UPDATE `#__helloworld` SET `ordering` = `id`;
The SQL Update statement above could result in gaps in our Ordering values, but this doesn't matter. The Ordering values don't have to be consecutive within a category, and over time the values will change as the ordering functionality is used.
Admin Helloworlds MVC
In our model we need to include the Ordering field in our database select. And as we're going to include the category within the filter fields, we need the category id in the select as well.
admin/models/helloworlds.php
<?php
/**
* @package Joomla.Administrator
* @subpackage com_helloworld
*
* @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
/**
* HelloWorldList Model
*
* @since 0.0.1
*/
class HelloWorldModelHelloWorlds extends JModelList
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @see JController
* @since 1.6
*/
public function __construct($config = array())
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'id',
'greeting',
'author',
'created',
'language',
'ordering',
'category_id',
'association',
'published'
);
}
parent::__construct($config);
}
protected function populateState($ordering = null, $direction = null)
{
$app = JFactory::getApplication();
// Adjust the context to support modal layouts.
if ($layout = $app->input->get('layout'))
{
$this->context .= '.' . $layout;
}
// Adjust the context to support forced languages.
$forcedLanguage = $app->input->get('forcedLanguage', '', 'CMD');
if ($forcedLanguage)
{
$this->context .= '.' . $forcedLanguage;
}
parent::populateState($ordering, $direction);
// If there's a forced language then define that filter for the query where clause
if (!empty($forcedLanguage))
{
$this->setState('filter.language', $forcedLanguage);
}
}
/**
* Method to build an SQL query to load the list data.
*
* @return string An SQL query
*/
protected function getListQuery()
{
// Initialize variables.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Create the base select statement.
$query->select('a.id as id, a.greeting as greeting, a.published as published, a.created as created,
a.checked_out as checked_out, a.checked_out_time as checked_out_time, a.ordering as ordering, a.catid as catid,
a.image as imageInfo, a.latitude as latitude, a.longitude as longitude, a.alias as alias, a.language as language')
->from($db->quoteName('#__helloworld', 'a'));
// Join over the categories.
$query->select($db->quoteName('c.title', 'category_title'))
->join('LEFT', $db->quoteName('#__categories', 'c') . ' ON c.id = a.catid');
// Join with users table to get the username of the author
$query->select($db->quoteName('u.username', 'author'))
->join('LEFT', $db->quoteName('#__users', 'u') . ' ON u.id = a.created_by');
// Join with users table to get the username of the person who checked the record out
$query->select($db->quoteName('u2.username', 'editor'))
->join('LEFT', $db->quoteName('#__users', 'u2') . ' ON u2.id = a.checked_out');
// Join with languages table to get the language title and image to display
// Put these into fields called language_title and language_image so that
// we can use the little com_content layout to display the map symbol
$query->select($db->quoteName('l.title', 'language_title') . "," .$db->quoteName('l.image', 'language_image'))
->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON l.lang_code = a.language');
// Join over the associations - we just want to know if there are any, at this stage
if (JLanguageAssociations::isEnabled())
{
$query->select('COUNT(asso2.id)>1 as association')
->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_helloworld.item'))
->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key')
->group('a.id');
}
// Filter: like / search
$search = $this->getState('filter.search');
if (!empty($search))
{
$like = $db->quote('%' . $search . '%');
$query->where('greeting LIKE ' . $like);
}
// Filter by published state
$published = $this->getState('filter.published');
if (is_numeric($published))
{
$query->where('a.published = ' . (int) $published);
}
elseif ($published === '')
{
$query->where('(a.published IN (0, 1))');
}
// Filter by language, if the user has set that in the filter field
$language = $this->getState('filter.language');
if ($language)
{
$query->where('a.language = ' . $db->quote($language));
}
// Filter by categories
$catid = $this->getState('filter.category_id');
if ($catid)
{
$query->where("a.catid = " . $db->quote($db->escape($catid)));
}
// Add the list ordering clause.
$orderCol = $this->state->get('list.ordering', 'greeting');
$orderDirn = $this->state->get('list.direction', 'asc');
$query->order($db->escape($orderCol) . ' ' . $db->escape($orderDirn));
return $query;
}
}
We add the category id to the filter fields, and also enable ordering by the Ordering column, correcting also the name of translated string association with ordering by greeting.
admin/models/forms/filter_helloworlds.xml
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="filter">
<field
name="search"
type="text"
label="COM_BANNERS_SEARCH_IN_TITLE"
hint="JSEARCH_FILTER"
class="js-stools-search-string"
/>
<field
name="published"
type="status"
label="JOPTION_SELECT_PUBLISHED"
description="JOPTION_SELECT_PUBLISHED_DESC"
onchange="this.form.submit();"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="language"
type="contentlanguage"
label="JOPTION_FILTER_LANGUAGE"
description="JOPTION_FILTER_LANGUAGE_DESC"
onchange="this.form.submit();"
>
<option value="">JOPTION_SELECT_LANGUAGE</option>
<option value="*">JALL</option>
</field>
<field
name="category_id"
type="category"
label="JOPTION_FILTER_CATEGORY"
extension="com_helloworld"
onchange="this.form.submit();"
published="0,1,2"
>
<option value="">JOPTION_SELECT_CATEGORY</option>
</field>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="COM_HELLOWORLD_LIST_FULL_ORDERING"
description="COM_HELLOWORLD_LIST_FULL_ORDERING_DESC"
onchange="this.form.submit();"
default="greeting ASC"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="ordering ASC">COM_HELLOWORLD_ORDERING_ASC</option>
<option value="ordering DESC">COM_HELLOWORLD_ORDERING_DESC</option>
<option value="greeting ASC">COM_HELLOWORLD_GREETING_ASC</option>
<option value="greeting DESC">COM_HELLOWORLD_GREETING_DESC</option>
<option value="id ASC">JGRID_HEADING_ID_ASC</option>
<option value="id DESC">JGRID_HEADING_ID_DESC</option>
<option value="published ASC">COM_HELLOWORLD_PUBLISHED_ASC</option>
<option value="published DESC">COM_HELLOWORLD_PUBLISHED_DESC</option>
<option value="author ASC">COM_HELLOWORLD_AUTHOR_ASC</option>
<option value="author DESC">COM_HELLOWORLD_AUTHOR_DESC</option>
<option value="created ASC">COM_HELLOWORLD_CREATED_ASC</option>
<option value="created DESC">COM_HELLOWORLD_CREATED_DESC</option>
<option value="language ASC">COM_HELLOWORLD_LANGUAGE_ASC</option>
<option value="language DESC">COM_HELLOWORLD_LANGUAGE_DESC</option>
<option value="association ASC">COM_HELLOWORLD_ASSOCIATION_ASC</option>
<option value="association DESC">COM_HELLOWORLD_ASSOCIATION_DESC</option>
</field>
<field
name="limit"