LOGIC Library

This site is the Logic involvement in sharing expertise and skills acquired in daily work. The goal is to create a solid knowledge base and share best practices in software development and systems management.

More info about us can be found on logicsistemi.it.

Developing MVC components for Joomla! 2.5 - Part 6

In this part of the tutorial we will complete the work on the list by adding controls that allow you to:

  • Divide the list into pages
  • Sort the list according to a specific column
  • Add, edit and delete data

Pagination

The standard control for pagination for the administration side of Joomla! is quite complete and add it to our management is extremely simple, requiring only view and template modification. Everything else is already implemented by our class JModelList.

Change the view in the following way:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
jimport( 'joomla.application.component.view' );
jimport( 'joomla.html.pagination' );
class RegistryViewPersons extends JView
{
    function display($tpl = null)
    {
        // Add required JS
        JHtml::_('behavior.framework');
        $this->pagination = $this->get('Pagination');
        $this->items = $this->get('Items');
        parent::display($tpl);
    }
}

At the beginning, through the new call of jimport, is includedthe PHP file required to generate HTML pagination controls. It will be used by the Model.

The call to JHTML class is for including the mootols framework required by Joomla!, This will enable pagination Javascript functions.

A little later is called the get function by passing it the value Pagination. As already stated for the value Items, this will call the function getPagination of the model, which returns an object JPagination that we will use in the template.

The template should be modified to insert the pagination in the footer of our management table. This is done by calling the method getListFooter of the JPagination object.

<?php
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
$option = JRequest::getCmd('option');
$view = JRequest::getCmd('view');
?>
<form action="index.php" method="post" name="adminForm" id="adminForm">
    <input type="hidden" name="option" value="<?=$option?>" />
    <input type="hidden" name="view" value="<?=$view?>" />
    <div id="editcell">    
        <table class="adminlist">
            <thead>
                <tr>
                    <th>NAME</th>
                    <th>SURNAME</th>
                    <th>ID</th>
                </tr>
            </thead>
            <tfoot>
                <tr>
                    <td colspan="3">
                        <?=$this->pagination->getListFooter()?>
                    </td>
                </tr>
            </tfoot>
            <tbody>
<?
        $k = 0;
        foreach ($this->items as &$row)
        {
?>
                <tr class="row<?=$k?>">
                    <td><?=$row->name?></td>
                    <td><?=$row->surname?></td>
                    <td><?=$row->id?></td>
                </tr>
<?
            $k = 1 - $k;
        }
?>
            </tbody>
        </table>
    </div>
</form>

In addition to the pagination were inserted some hidden fields into the form previously created. These fields are used to store information about the component you are viewing (option) and the view of this component (view) during the different submit. Both parameters are retrieved from the URL.

To see how this part is working you can copy the two files on your website (in /administrator/components/com_registry/views/persons) and test the page, but first manually add some records to the table to be able to show different pages.

Ordering

Add sorting requires some additional steps and the modification of the model.

We start again from the view:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
jimport( 'joomla.application.component.view' );
jimport( 'joomla.html.pagination' );
class RegistryViewPersons extends JView
{
    function display($tpl = null)
    {
        JHtml::_('behavior.framework');
        $this->pagination = $this->get('Pagination');
        $this->items = $this->get('Items');
        $this->state = $this->get('State');
        parent::display($tpl);
    }
}

We added a new call to get. This time we recover the state informations by using our model. These method returns an object in which the model stores status information, including those necessary to order our table. This information will be kept in session, so the sort (as well as pagination) will be maintained each time we return to our page.

Let's also modify the template:

<?php 
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

$option = JRequest::getCmd('option');
$view = JRequest::getCmd('view');
$listOrder = $this->state->get('list.ordering');
$listDirn = $this->state->get('list.direction');
?>
<form action="index.php" method="post" name="adminForm" id="adminForm">
    <input type="hidden" name="option" value="<?=$option?>" />
    <input type="hidden" name="task" value="" />
    <input type="hidden" name="view" value="<?=$view?>" />
    <input type="hidden" name="filter_order" value="<?=$listOrder?>" />
    <input type="hidden" name="filter_order_Dir" value="<?=$listDirn?>" />    
    <div id="editcell">    
        <table class="adminlist">
            <thead>
                <tr>
                    <th>
                        <?=JHtml::_('grid.sort', 'NAME', 'name', $listDirn, $listOrder); ?>
                    </th>
                    <th>
                        <?=JHtml::_('grid.sort', 'SURNAME', 'surname', $listDirn, $listOrder); ?>
                    </th>
                    <th>
                        <?=JHtml::_('grid.sort', 'ID', 'id', $listDirn, $listOrder); ?>
                    </th>
                </tr>
            </thead>
            <tfoot>
                <tr>
                    <td colspan="3">
                        <?=$this->pagination->getListFooter()?>
                    </td>
                </tr>
            </tfoot>
            <tbody>
<?
        $k = 0;
        foreach ($this->items as &$row)
        {
?>
                <tr class="row<?=$k?>">
                    <td><?=$row->name?></td>
                    <td><?=$row->surname?></td>
                    <td><?=$row->id?></td>
                </tr>
<?
            $k = 1 - $k;
        }
?>
            </tbody>
        </table>
    </div>
</form>

First of all were retrieved information about the field to be used to sort data and the sort direction (ascending or descending). These informations has been inserted in 2 hidden fields to keep them during the submits. The names of these fields must be set as shown, cause default Joomla! methods expect to find these fields to set ordering before submit.

We also added the hidden field task. You certainly remember that it's used to determine the action the controller must perform. In our case it is always the default, but the JavaScript functions looks for this field and set its value.

The titles of the columns are displayed by calling JHTML class with the "grid.sort" parameter. These calls generate HTML and JavaScript code necessary to manage ordering, including the addition of the appropriate icons. The second parameter is the label to be displayed, while the third will be the value that is passed during the submit. The remaining parameters allow to display the right icon based on the current state.

Last step is to modify the model as follows:

<?php
defined('_JEXEC') or die();
jimport( 'joomla.application.component.modellist' );
class RegistryModelPersons extends JModelList
{
    public function __construct($config = array())
    {
        if (empty($config['filter_fields'])) {
            $config['filter_fields'] = array('id', 'name', 'surname');
        }
        parent::__construct($config);
    }
    function getListQuery()
    {
        $db = JFactory::getDBO();
        $query = $db->getQuery(true);
        $query->select('id, name, surname');
        $query->from('#__registry_persons');
        $query->order($this->getState('list.ordering', 'id') .
            ' ' . $this->getState('list.direction', 'ASC'));
       return $query;
    }
}

Changes to getListQuery are simples: has been added the order part for the query. Its values are set by retrieving the status information from the model. Were also added 2 parameters that set the default sort using the id field and the ASC direction.

The class constructor has been included to indicate what are the fields for which it is allowed to specify the sort order. I believe this system is needed only to prevent unwanted ordering and to increase the security of the system.

You can try these changes by copying the 3 files modified and clicking on the column headings. However, I leave you a little exercise: the first time you enter the page does not appear the correct icon for the default sort column ID. How can you do to make it works?

Actions on records

As a final step we add buttons that will allow us to operate on records. What we will do will not, at present, work: to complete it will introduce in the next post some PHP code to execute real operations and some pieces of HTML.

To insert the buttons modify the view as follows:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
jimport( 'joomla.application.component.view' );
jimport( 'joomla.html.pagination' );
class RegistryViewPersons extends JView
{
    function display($tpl = null)
    {
        // Toolbar
        JToolBarHelper::title( JText::_( 'PERSONS' ), 'generic.png' );        
        JToolBarHelper::addNewX('person.add');
        JToolBarHelper::editListX('person.edit');
        JToolBarHelper::deleteList( JText::_( 'PERSONS_CONFIRM_DELETE' ),
          'persons.delete' );
        $this->pagination = $this->get('Pagination');
        $this->items = $this->get('Items');
        $this->state = $this->get('State');
        parent::display($tpl);
    }
}

We use the class JToolBarHelper that allows us to put a toolbar in the space, reserved for it, above our table.

The first call sets the title with an icon.

The second and third set the buttons to create a new record or edit the selected record. The additional X is used in the call to ensure that the Joomla menu is disabled to prevent further operations moving to the detail page.

The fourth call sets the delete button with a message of confirmation.

The meaning of some attributes such as 'person.add' or 'persons.delete' will be explained later. For now copy them respecting plural and singular forms. Is missed also the ability to select records to edit or delete. We will also put this to work in the next post (I think this is already quite large!).

For labels and sentences used, such as confirmation of cancellation, you may have noticed that the strings were always used uppercase and without spaces. This is necessary because these strings are then replaced using the translation mechanism integrated in Joomla!, I will tell you more about that later.

Note, finally, that has been removed the call to JHTML for the framework mootols. It is already entered by calls that create the buttons and it is therefore unnecessary.

Creating the package

The structure of our package has not changed, however, you must insert a blank file in the updates folder:

com_registry
  admin
    controller.php
    index.html
    registry.php
    models
      persons.php
    sql
      install.sql
      uninstall.sql
      updates
        0.0.4.sql 
        0.0.5.sql
    views
      index.html
      persons
        index.html
        view.html.php
        tmpl
          default.php
          index.html
  site
    registry.php
    index.html
  registry.xml

registry.xml should be changed simply by updating the version number:

<?xml version="1.0" encoding="UTF-8"?>
<install type="component" version="2.5.0" method="upgrade">
    <name>Registry</name>
    <author>Edy Incoletti</author>
    <authorEmail>edy.incoletti@logicsistemi.it</authorEmail>
    <authorUrl>http://library.logicsistemi.it</authorUrl>
    <creationDate>March 2012</creationDate>
    <version>0.0.5</version>
    <description>Registry management for the tutorial.</description>
    
    <files folder="site">
        <filename>index.html</filename>
        <filename>registry.php</filename>
    </files>

    <install folder="admin">
        <sql>
            <file charset="utf8" driver="mysql">sql/install.sql</file>
        </sql>
    </install>
    <uninstall folder="admin">
        <sql>
            <file charset="utf8" driver="mysql">sql/uninstall.sql</file>
        </sql>
     </uninstall>
    <update>
        <schemas>
            <schemapath type="mysql">sql/updates</schemapath>
        </schemas>
    </update>

    <administration>
        <files folder="admin">
            <filename>index.html</filename>
            <filename>registry.php</filename>
            <filename>controller.php</filename>
            <folder>models</folder>
            <folder>sql</folder>
            <folder>views</folder>
        </files>
    </administration>
</install>

This time it is again possible to install the package without have to remove the existing using your package or with this one.

Comments   

 
#1 kamaljit laishram 2013-07-20 06:42
i set default sort icon

protected function populateState
($ordering = null, $direction = null) {
parent::populateState('name', 'ASC');
}
Quote