Implementing item ordering at backend | Joomla 3.x extension development crash course.

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 Joomla JController class, how to access a sub controller from the task request variable, using the dot notation. The main function of sub controller is same as main controller, just it is used to easily organize 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 taks, originating from breeds 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 controller library. After that we are extending our sub controller class from the JControllerAdmin class. Controller name has a special format, like, the name of component, "Breed", the word "Controller" and then the name of sub controller, "Breeds". What we are doing in this class is, we are overriding 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 getModel() function through the "model" property and pass a specific configuration option called “ignore_request”. It is always a good practice, when the sub controller is in use, model should not be make to look at the request so that controller should have complete control over model state and to do that, we have passed the configuration option “ignore_request”, 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 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 update 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 form, which are then pickedup and interpreted by model and then passed to the view for display. The xml based fors 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 aour all fields related code. But currently we want only the id field, with the value of the mapping table id field. Its value will be updated when we will perform a change order operation and will be updated in the table as well. The concept of mapping the field names with that of the table columns is called Object relational mapping (ORM) and is the base of joomla 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 that we have created a form in an xml format, the next step is to load it. We have created a new file, called breed.php in 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, suppose user has missed any required field while filling out the form, it will be redirected to the same form to fill this field. Now the data of other fields will be stored in this session which could be pulled out and fill the form. The next argument is the name of 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 comes our actual implementation of ordering the rows. For this purpose, as you know that in designing the database table section, we have created a field named "ordering" with int datatype, meant to hold only integer value. So, whenever you want to implement ordering, either in component backend or frontend list view, you must have to create a field named "ordering" with datatype int, in your corresponding database table. 

On line 15 of 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, when we are changing 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 are using JHtml::_ class loader method and as I have discussed before that underscore(_) is a static method used by different Joomla classes for enabling a quick access to a number of methods in the sub packeage of respective class and in the JHtml case, these could be JHtmlGrid or JHtmlBehavior etc.

The first argument is the sortablelist.sortable, there is a call to JHtmlSortablelist class sortable method, located in /libraries/cms/html/sortablelist.php file. It is a utility class, meant to create a sortable table list. Thesecond argument is a reference to the id of our table on which we want to implement column ordering. Then there is areference to form and after that, there is the current sorting status and then, the url on 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>

cccccccccccccccccc

	<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>
- - - - -

 

 

Download Code

You have no rights to post comments

Enjoy best web development services at an affordable price. Looking forward to build a good relationship and serve you better...

Copyright © 2017. All rights reserved.