Développement d'un composant MVC - Ajout d'un processus de traitement
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.
Ce didacticiel fait partie de la série de didacticiels sur le Développement d'un Composant MVC pour Joomla! 3.x. Vous êtes invité à lire les articles précédents de cette série avant de lire celui-ci.
In this step we add a helloworld batch process to the backend. An accompanying video is available at Adding a batch process.
Introduction
Joomla provides a number of facilities to enable administrators to update articles and other types of item in batch. These include:
- moving or copying records into records with a selected category
- setting the language and/or access for the selected records
- adding a tag to the selected records
In this step we add these facilities into our helloworld component and also provide a batch process to enable the administrator to set the latitude and longitude.
Approche
To implement the batch processes we have to consider the following aspects.
Batch Button and Modal
- We show a Batch button in the toolbar on our helloworlds view. The administrator can click the checkboxes of the helloworld records to process in batch, and then click Batch to proceed.
- When the Batch button is clicked we want a modal to appear with the available options, so we must add the html for the Bootstrap modal. We'll do this in the helloworlds layout file, and utilise a couple of new subsidiary layouts for the modal body and footer.
The modal body will contain the html elements for the various options – eg set language, set access, set lat/long, etc. The elements for setting the language, access, category and tag are all standard Joomla library layouts within the /layouts directory tree. For setting the lat/long position we'll write our own layout file which we'll put in a new admin/layouts directory (and we have to remember to include this new folder in the main helloworld.xml manifest file).
The modal footer will contain the Cancel (for cancelling the operation) and Process (for starting the batch process) buttons.
Handling the HTTP POST in the Controller

When the Process button is pressed the javascript code will submit the form and so initiate an HTTP POST request to the server with parameters which include
- the ids of the records which have been selected for batch processing
- the batch options which have been chosen
- the task variable set to task=helloworld.batch
Joomla will route this to a batch() method in admin/controllers/helloworld.php.
In our helloworld controller batch() method we do the following:
- set up the model to be the helloworld model
- set up the redirect to present the helloworlds view again, once the batch processing is complete
- call the parent batch method, passing the model as parameter
The parent batch method (in JControllerForm) will obtain the POST params, perform some verification of them, and then call the batch() method within the passed model, passing the POST parameters.
Executing the batch processes in the Model
The way the Joomla batch model functionality works is that the JModelAdmin class has a property $batch_commands which is an associative array mapping the index of the batch parameters to the method which will perform that batch operation.
protected $batch_commands = array( 'assetgroup_id' => 'batchAccess', 'language_id' => 'batchLanguage', 'tag' => 'batchTag', );
So if in the batch modal an administrator sets the language selector to one of the available languages then batch[language_id] is set within the HTTP POST parameters. The model code looks up "language_id" in this $batch_commands property, finds "batchLanguage" and then proceeds to call the method batchLanguage().
In our case we will have a method called batchPosition() which will set the lat/long for the selected records, so we need to ensure that:
- the html input elements are defined so that batch[position] parameters are sent in the HTTP POST
- we add an extra record to the $batch_commands array, namely 'position' => 'batchPosition'.
The first aspect is done where we define the html of the input elements in our modal body.
The second aspect is done in a batch() method which we write in our helloworld model. This adds in the extra array element and then calls the parent::batch() to initiate all the batch operations.
Finally we must write our batchPosition() method to update the set of records with the passed-in latitude and longitude values.
Bouton de traitement
We add the batch button in our helloworlds view. Because this is a custom button we need to get a handle on the toolbar instance, and then use appendButton(), as we can't use a ToolbarHelper function for this.
admin/views/helloworlds/view.html.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');
/**
* HelloWorlds View
*
* @since 0.0.1
*/
class HelloWorldViewHelloWorlds extends JViewLegacy
{
/**
* Display the Hello World view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*/
function display($tpl = null)
{
// Get application
$app = JFactory::getApplication();
// Get data from the model
$this->items = $this->get('Items');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
// What Access Permissions does this user have? What can (s)he do?
$this->canDo = JHelperContent::getActions('com_helloworld');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
// Set the sidebar submenu and toolbar, but not on the modal window
if ($this->getLayout() !== 'modal')
{
HelloWorldHelper::addSubmenu('helloworlds');
$this->addToolBar();
}
else
{
// If it's being displayed to select a record as an association, then forcedLanguage is set
if ($forcedLanguage = $app->input->get('forcedLanguage', '', 'CMD'))
{
// Transform the language selector filter into an hidden field, so it can't be set
$languageXml = new SimpleXMLElement('<field name="language" type="hidden" default="' . $forcedLanguage . '" />');
$this->filterForm->setField($languageXml, 'filter', true);
// Also, unset the active language filter so the search tools is not open by default with this filter.
unset($this->activeFilters['language']);
}
}
// Prepare a mapping from parent id to the ids of its children
$this->ordering = array();
foreach ($this->items as $item)
{
$this->ordering[$item->parent_id][] = $item->id;
}
// Display the template
parent::display($tpl);
// Set the document
$this->setDocument();
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolBar()
{
$title = JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS');
$bar = JToolbar::getInstance('toolbar');
if ($this->pagination->total)
{
$title .= "<span style='font-size: 0.5em; vertical-align: middle;'>(" . $this->pagination->total . ")</span>";
}
JToolBarHelper::title($title, 'helloworld');
if ($this->canDo->get('core.create'))
{
JToolBarHelper::addNew('helloworld.add', 'JTOOLBAR_NEW');
}
if ($this->canDo->get('core.edit'))
{
JToolBarHelper::editList('helloworld.edit', 'JTOOLBAR_EDIT');
}
if ($this->canDo->get('core.delete'))
{
JToolBarHelper::deleteList('', 'helloworlds.delete', 'JTOOLBAR_DELETE');
}
if ($this->canDo->get('core.edit') || JFactory::getUser()->authorise('core.manage', 'com_checkin'))
{
JToolBarHelper::checkin('helloworlds.checkin');
}
// Add a batch button
if ($this->canDo->get('core.create') && $this->canDo->get('core.edit')
&& $this->canDo->get('core.edit.state'))
{
// we use a standard Joomla layout to get the html for the batch button
$layout = new JLayoutFile('joomla.toolbar.batch');
$batchButtonHtml = $layout->render(array('title' => JText::_('JTOOLBAR_BATCH')));
$bar->appendButton('Custom', $batchButtonHtml, 'batch');
}
if ($this->canDo->get('core.admin'))
{
JToolBarHelper::divider();
JToolBarHelper::preferences('com_helloworld');
}
}
/**
* Method to set up the document properties
*
* @return void
*/
protected function setDocument()
{
$document = JFactory::getDocument();
$document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION'));
}
}
Batch Modal
We add the html for the batch modal into the helloworlds layout file.
admin/views/helloworlds/tmpl/default.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');
use Joomla\Registry\Registry;
JHtml::_('formbehavior.chosen', 'select');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$user = JFactory::getUser();
$userId = $user->get('id');
$saveOrder = ($listOrder == 'lft' && strtolower($listDirn) == 'asc');
if ($saveOrder)
{
$saveOrderingUrl = 'index.php?option=com_helloworld&task=helloworlds.saveOrderAjax&tmpl=component';
// pass true as parameter 7 to indicate that we have a nested set
JHtml::_('sortablelist.sortable', 'helloworldList', 'adminForm', strtolower($listDirn), $saveOrderingUrl, false, true);
}
$assoc = JLanguageAssociations::isEnabled();
$authorFieldwidth = $assoc ? "10%" : "25%";
JLoader::register('JHtmlHelloworlds', JPATH_ADMINISTRATOR . '/components/com_helloworld/helpers/html/helloworlds.php');
?>
<form action="index.php?option=com_helloworld&view=helloworlds" method="post" id="adminForm" name="adminForm">
<div id="j-sidebar-container" class="span2">
<?php echo JHtmlSidebar::render(); ?>
</div>
<div id="j-main-container" class="span10">
<div class="row-fluid">
<div class="span12">
<?php echo JText::_('COM_HELLOWORLD_HELLOWORLDS_FILTER'); ?>
<?php
echo JLayoutHelper::render(
'joomla.searchtools.default',
array('view' => $this)
);
?>
</div>
</div>
<table class="table table-striped table-hover" id="helloworldList">
<thead>
<tr>
<th width="1%">
<?php echo JHtml::_('searchtools.sort', '', 'lft', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-menu-2'); ?>
</th>
<th width="1%"><?php echo JText::_('COM_HELLOWORLD_NUM'); ?></th>
<th width="1%">
<?php echo JHtml::_('grid.checkall'); ?>
</th>
<th width="10%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_HELLOWORLDS_NAME', 'greeting', $listDirn, $listOrder); ?>
</th>
<th width="10%">
<?php echo JText::_('COM_HELLOWORLD_HELLOWORLDS_POSITION'); ?>
</th>
<th width="10%">
<?php echo JText::_('COM_HELLOWORLD_HELLOWORLDS_IMAGE'); ?>
</th>
<th width="20%">
<?php echo JHtml::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'access', $listDirn, $listOrder); ?>
</th>
<?php if ($assoc) : ?>
<th width="10%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_HELLOWORLDS_ASSOCIATIONS', 'association', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<th width="<?php echo $authorFieldwidth; ?>">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_AUTHOR', 'author', $listDirn, $listOrder); ?>
</th>
<th width="10%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_LANGUAGE', 'language', $listDirn, $listOrder); ?>
</th>
<th width="10%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_CREATED_DATE', 'created', $listDirn, $listOrder); ?>
</th>
<th width="5%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_PUBLISHED', 'published', $listDirn, $listOrder); ?>
</th>
<th width="2%">
<?php echo JHtml::_('searchtools.sort', 'COM_HELLOWORLD_ID', 'id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="5">
<?php echo $this->pagination->getListFooter(); ?>
</td>
</tr>
</tfoot>
<tbody>
<?php if (!empty($this->items)) : ?>
<?php foreach ($this->items as $i => $row) :
$link = JRoute::_('index.php?option=com_helloworld&task=helloworld.edit&id=' . $row->id);
$row->image = new Registry;
$row->image->loadString($row->imageInfo);
// create a list of the parents up the hierarchy to the root
if ($row->level > 1)
{
$parentsStr = '';
$_currentParentId = $row->parent_id;
$parentsStr = ' ' . $_currentParentId;
for ($j = 0; $j < $row->level; $j++)
{
foreach ($this->ordering as $k => $v)
{
$v = implode('-', $v);
$v = '-' . $v . '-';
if (strpos($v, '-' . $_currentParentId . '-') !== false)
{
$parentsStr .= ' ' . $k;
$_currentParentId = $k;
break;
}
}
}
}
else
{
$parentsStr = '';
}
?>
<tr class="row<?php echo $i % 2; ?>" sortable-group-id="<?php echo $row->parent_id; ?>" item-id="<?php echo $row->id; ?>" parents="<?php echo $parentsStr; ?>" level="<?php echo