Implementing item ordering at backend
Files to create / update
create breeds.php /administrator/controllers/breeds.php
create breed.php /administrator/tables/breed.php
create breed.php /administrator/models/breed.php
create breed.php /administrator/models/forms/breed.xml
update breeds.php /administrator/models/breeds.php
update view.html.php /administrator/views/breeds/view.html.php
update default.php /administrator/views/breeds/tmpl/default.php
update breed.xml /breed.xml
Files Detail
/administrator/controllers/breeds.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.controlleradmin');
use Joomla\Utilities\ArrayHelper;
class BreedControllerBreeds extends JControllerAdmin
{
public function getModel($name = 'breed', $prefix = 'BreedModel', $config = array())
{
$model = parent::getModel($name, $prefix, array('ignore_request' => true));
return $model;
}
}
We have gone through the main controller before. We can declare any task in that controller, but it is better to separate the tasks connected to respective views into their corresponding sub-controllers, also known as application controllers. It is already programmed in the Joomla JController class how to access a sub-controller from the task request variable using the dot notation. A sub-controller’s primary function is the same as that of the main controller; it is simply used to organise the code.
All sub-controllers are grouped in a “controllers” folder, which is placed in the component root directory. We have created a controller in the respective directory, called breeds.php, as listed above. It will be used to process all tacos that originate from the breed’s point of view.We have to also put an index.html file in this folder.
As you can see in the code, we have used jimport to import the controller library. After that, we are extending our sub-controller class from the JControllerAdmin class. A controller’s name follows a specific format, similar to the name of a component, “Breed,” the word “Controller,” and then the name of a sub-controller, “Breeds.” What we are doing in this class is overriding the getModel method in the JControllerAdmin class. To this method, we are passing the model name “breed” in the argument list and then the class prefix, and after that, there is a configuration array. Then we are calling the parent’s getModel() function through the “model” property and passing a specific configuration option called “ignore_request.” When using the sub-controller, it is always a good practise to prevent the model from looking at the request so that the controller has complete control over the model’s state; to accomplish this, we have passed the configuration option “ignore_request,” which has a value of true.
/administrator/tables/breed.php
<?php
defined('_JEXEC') or die;
use Joomla\Utilities\ArrayHelper;
class BreedTablebreed extends JTable
{
public function __construct(&$db)
{
parent::__construct('#__breed_breed', 'id', $db);
}
}
In this step, we are creating new folder called “tables” under the component folder, to contain any table files that the component will use. Then we are creating a file in the tables folder, to connect with our breeds table, called “breed.php”. The constructor in the table class calls the parent class constructor and provides name of the database table and the primary key as arguments. We call the table name with its name, prefix with “#__” string. Joomla replaces this string with the database prefix which it picks from configuration file.
/administrator/models/forms/breed.xml
<?xml version="1.0" encoding="utf-8"?>
<form>
<fieldset>
<field name="id" type="text" default="0" label="COM_BREED_FORM_LBL_BREED_ID"
readonly="true" class="readonly"
description="JGLOBAL_FIELD_ID_DESC" />
</fieldset>
</form>
Now, in the change order action, there would be an update to the database table for the order of a specific record. To accomplish this, there must be a form holding the id value of that record and updating its order status on the basis of that id. So, in this step, we are going to create a small form here to hold our ID field.
In Joomla, forms are created in an XML format, which is then picked up and interpreted by the model and then passed to the view for display. The xml-based forms are stored in the forms folder in the models directory.
In the above-mentioned code, we have started an xml file with an xml prolog, and from the next line, we are starting the form and then a fieldset, which will be wrapping up all field-related code. However, for the time being, we only need the id field to contain the value of the mapping table id field. Its value will be updated when we perform a change order operation and will be updated in the table as well. The concept of mapping the field names with those of the table columns is called object relational mapping (ORM) and is the base of Joomla’s CRUD-based operations.
/administrator/models/breed.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.modeladmin');
class BreedModelBreed extends JModelAdmin
{
protected $text_prefix = 'COM_BREED';
protected $item = null;
public function getTable($type = 'Breed', $prefix = 'BreedTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
public function getForm($data = array(), $loadData = true)
{
// Initialise variables.
$app = JFactory::getApplication();
// Get the form.
$form = $this->loadForm(
'com_breed.breed', 'breed',
array('control' => 'jform',
'load_data' => $loadData
)
);
if (empty($form))
{
return false;
}
return $form;
}
}
After we have created a form in XML format, the next step is to load it. We have created a new file, called breed.php, in the models folder to deal with forms and data. In this file, on line 20, there is a method called getForm, and in it, on line 26, we are actually loading the form. In its first argument, we are setting up the context. In this case, com_breed.breed would be the session variable, which will store any data entered through the form.
The benefit of this is that if the user misses any required field while filling out the form, he will be redirected to the same form to fill it out. Other fields’ data will now be saved in this session and can be retrieved and filled in. The next argument is the name of the form we want to load. As we want to load breed.xml, we are simply writing it as “breed” here. Next is the configuration array.
/administrator/views/breeds/tmpl/default.php
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', 'select');
$user = JFactory::getUser();
$userId = $user->get('id');
$saveOrder = $listOrder == 'a.`ordering`';
In the default.php template file, there is our actual implementation of ordering the rows. For this purpose, as you know, in designing the database table section, we have created a field named “ordering” with an int datatype, meant to hold only integer values. So, whenever you want to implement ordering, either in the component backend or the frontend list view, you must create a field named “ordering” with a datatype of int in your corresponding database table.
On line 15 of the above-mentioned code, we are setting the value of $listOrder to be equal to a.ordering and then passing this value to $saveOrder. The reason is that when we change the order of a column, the records must be sorted according to the ordering column or field of the database table.
if ($saveOrder)
{
$saveOrderingUrl = 'index.php?option=com_breed&task=breeds.saveOrderAjax&tmpl=component';
JHtml::_('sortablelist.sortable', 'breedList', 'adminForm', strtolower($listDirn), $saveOrderingUrl);
}
?>
<script type="text/javascript">
Joomla.orderTable = function () {
table = document.getElementById("sortTable");
direction = document.getElementById("directionTable");
order = table.options[table.selectedIndex].value;
if (order != '<?php echo $listOrder; ?>') {
dirn = 'asc';
} else {
dirn = direction.options[direction.selectedIndex].value;
}
Joomla.tableOrdering(order, dirn, '');
};
</script>
On line 20, we use the JHtml::_ class loader method, and as previously discussed, underscore(_) is a static method used by various Joomla classes to enable quick access to a number of methods in the respective class’s subpackage; in the JHtml case, these could be JHtmlGrid or JHtmlBehavior, etc.
The first argument is the sortablelist.sortable, and there is a call to the JHtmlSortablelist class’s sortable method, located in the /libraries/cms/html/sortablelist.php file. It is a utility class meant to create a sortable table list. The second argument is a reference to the id of our table, on which we want to implement column ordering. Then there’s a form reference, then the current sorting status, and finally the url to which an ajax call will be made to update the ordering value of a specific record.
<?php if (isset($this->items[0]->ordering)): ?>
<th width="1%" class="nowrap center hidden-phone">
<?php echo JHtml::_('grid.sort', '<i class="icon-menu-2"></i>', 'a.`ordering`', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?>
</th>
<?php endif; ?>
<th width="1%" class="hidden-phone">
<input type="checkbox" name="checkall-toggle" value=""
title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)"/>
</th> <tr class="row<?php echo $i % 2; ?>">
<?php if (isset($this->items[0]->ordering)) : ?>
<td class="order nowrap center hidden-phone">
<?php
$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>
Then we have created our main ordering code from line 102 to 123 which is currently residing first, in the list which will actually create a drag icon in the first cell of each row. If the column is not sorted according to the ordering column, the ordering arrows will become inactive and it means that drag and drop ordering process would be deactivated.
Changes to /breed.xml
- - - - -
<files folder="administrator">
<filename>index.html</filename>
<filename>breed.php</filename>
<folder>sql</folder>
<filename>controller.php</filename>
<folder>views</folder>
<folder>models</folder>
<folder>controllers</folder>
<folder>tables</folder>
</files>
- - - - -
Next –> Implementing search feature and filters functionality at backend