Customize backend Component in Joomla! 1.5

Exclusive offer: get 50% off this eBook here
Mastering Joomla! 1.5 Extension and Framework Development

Mastering Joomla! 1.5 Extension and Framework Development — Save 50%

The Professional Guide to Programming Joomla!

€20.99    €10.50
by Chuck Lanham James Kennard | June 2010 | Joomla! Open Source

Joomla! is one of the world's top open source content management systems. The main sources of the PHP MySQL application's success are its comprehensive extension libraries, which extend Joomla! far beyond content management, and it's very active forums where one can easily tap into the knowledge of other Joomla! users, administrators, and developers.

In this article by Chuck Lanham and James Kennard, author of Mastering Joomla! 1.5 Extension and Framework Development, we will cover:

  • Pagination using JPagination class
  • How to Modify the Submenu
  • The joomla.html library
  • How to Build better layouts and templates

(Read more interesting articles on Joomla! 1.5here.)

Itemized data

Most components handle and display itemized data. Itemized data is data having many instances; most commonly this reflects rows in a database table. When dealing with itemized data there are three areas of functionality that users generally expect:

  • Pagination
  • Ordering
  • Filtering and searching

In this section we will discuss each of these areas of functionality and how to implement them in the backend of a component.

Pagination

To make large amounts of itemized data easier to understand, we can split the data across multiple pages. Joomla! provides us with the JPagination class to help us handle pagination in our extensions.

There are four important attributes associated with the JPagination class:

  • limitstart: This is the item with which we begin a page, for example the first page will always begin with item 0.
  • limit: This is the maximum number of items to display on a page.
  • total: This is the total number of items across all the pages.
  • _viewall: This is the option to ignore pagination and display all items.

Before we dive into piles of code, let's take the time to examine the listFooter, the footer that is used at the bottom of pagination lists:

Customize backend Component in Joomla! 1.5

The box to the far left describes the maximum number of items to display per page (limit). The remaining buttons are used to navigate between pages. The final text defines the current page out of the total number of pages.

The great thing about this footer is we don't have to work very hard to create it! We can use a JPagination object to build it. This not only means that it is easy to implement, but that the pagination footers are consistent throughout Joomla!. JPagination is used extensively by components in the backend when displaying lists of items.

In order to add pagination to our revues list we must make some modifications to our backend revues model. Our current model consists of one private property $_revues and two methods: getRevues() and delete(). We need to add two additional private properties for pagination purposes. Let's place them immediately following the existing $_revues property:

/** @var array of revue objects */
var $_revues = null;
/** @var int total number of revues */
var $_total = null;
/** @var JPagination object */
var $_pagination = null;

Next we must add a class constructor, as we will need to retrieve and initialize the global pagination variables $limit and $limitstart. JModel objects store a state object in order to record the state of the model. It is common to use the state variables limit and limitstart to record the number of items per page and starting item for the page.

We set the state variables in the constructor:

/**
* Constructor
*/
function __construct()
{
global $mainframe;

parent::__construct();
// Get the pagination request variables
$limit = $mainframe->getUserStateFromRequest(
'global.list.limit',
'limit', $mainframe->getCfg('list_limit'));
$limitstart = $mainframe->getUserStateFromRequest(
$option.'limitstart', 'limitstart', 0);
// Set the state pagination variables
$this->setState('limit', $limit);
$this->setState('limitstart', $limitstart);
}

Remember that $mainframe references the global JApplication object. We use the getUserStateFromRequest() method to get the limit and limitstart variables.

We use the user state variable, global.list.limit, to determine the limit. This variable is used throughout Joomla! to determine the length of lists. For example, if we were to view the Article Manager and select a limit of five items per page, if we move to a different list it will also be limited to five items.

If a value is set in the request value limit (part of the listFooter), we use that value. Alternatively we use the previous value, and if that is not set we use the default value defined in the application configuration.

The limitstart variable is retrieved from the user state value $option, plus .limitstart. The $option value holds the component name, for example com_content. If we build a component that has multiple lists we should add an extra level to this, which is normally named after the entity.

If a value is set in the request value limitstart (part of the listFooter) we use that value. Alternatively we use the previous value, and if that is not set we use the default value 0, which will lead us to the first page.

The reason we retrieve these values in the constructor and not in another method is that in addition to using these values for the JPagination object, we will also need them when getting data from the database.

In our existing component model we have a single method for retrieving data from the database, getRevues(). For reasons that will become apparent shortly we need to create a private method that will build the query string and modify our getRevues() method to use it.

/**
* Builds a query to get data from #__boxoffice_revues
* @return string SQL query
*/
function _buildQuery()
{
$db =& $this->getDBO();
$rtable = $db->nameQuote('#__boxoffice_revues');
$ctable = $db->nameQuote('#__categories');

$query = ' SELECT r.*, cc.title AS cat_title'
. ' FROM ' . $rtable. ' AS r'
. ' LEFT JOIN '.$ctable.' AS cc ON cc.id=r.catid;

return $query;
}

We now must modify our getRevues() method:

/**
* Get a list of revues
*
* @access public
* @return array of objects
*/
function getRevues()
{
// Get the database connection
$db =& $this->_db;
if( empty($this->_revues) )
{
// Build query and get the limits from current state
$query = $this->_buildQuery();
$limitstart = $this->getState('limitstart');
$limit = $this->getState('limit');
$this->_revues = $this->_getList($query,
$limitstart,
$limit);
}
// Return the list of revues
return $this->_revues;
}

We retrieve the object state variables limit and limitstart and pass them to the private JModel method _getList(). The _getList() method is used to get an array of objects from the database based on a query and, optionally, limit and limitstart.

The last two parameters will modify the first parameter, a query, in such a way that we only return the desired results. For example if we requested page 1 and were displaying a maximum of five items per page, the following would be appended to the query: LIMIT 0, 5.

To handle pagination we need to add a method called getPagination() to our model. This method will handle items we are trying to paginate using a JPagination object. Here is our code for the getPagination() method:

/**
* Get a pagination object
*
* @access public
* @return pagination object
*/
function getPagination()
{
if (empty($this->_pagination))
{
// Import the pagination library
jimport('joomla.html.pagination');
// Prepare the pagination values
$total = $this->getTotal();
$limitstart = $this->getState('limitstart');
$limit = $this->getState('limit');
// Create the pagination object
$this->_pagination = new JPagination($total,
$limitstart,
$limit);
}
return $this->_pagination;
}

There are three important aspects to this method. We use the private property $_pagination to cache the object, we use the getTotal() method to determine the total number of items, and we use the getState() method to determine the number of results to display.

The getTotal() method is a method that we must define in order to use. We don't have to use this name or this mechanism to determine the total number of items. Here is one way of implementing the getTotal() method:

/**
* Get number of items
*
* @access public
* @return integer
*/
function getTotal()
{
if (empty($this->_total))
{
$query = $this->_buildQuery();
$this->_total = $this->_getListCount($query);
}
return $this->_total;
}

This method calls our model's private method _buildQuery() to build the query, the same query that we use to retrieve our list of revues. We then use the private JModel method _getListCount()to count the number of results that will be returned from the query.

We now have all we need to be able to add pagination to our revues list except for actually adding pagination to our list page. We need to add a few lines of code to our revues/view.html.php file. We will need to access to global user state variables so we must add a reference to the global application object as the first line in our display method:

global $mainframe;

Next we need to create and populate an array that will contain user state information. We will add this code immediately after the code that builds the toolbar:

// Prepare list array
$lists = array();

// Get the user state
$filter_order = $mainframe->getUserStateFromRequest(
$option.'filter_order',
'filter_order', 'published');
$filter_order_Dir = $mainframe->getUserStateFromRequest(
$option.'filter_order_Dir',
'filter_order_Dir', 'ASC');

// Build the list array for use in the layout
$lists['order'] = $filter_order;
$lists['order_Dir'] = $filter_order_Dir;
// Get revues and pagination from the model
$model =& $this->getModel( 'revues' );
$revues =& $model->getRevues();
$page =& $model->getPagination();

// Assign references for the layout to use
$this->assignRef('lists', $lists);
$this->assignRef('revues', $revues);
$this->assignRef('page', $page);

After we create and populate the $lists array, we add a variable $page that receives a reference to a JPagination object by calling our model's getPagination() method. And finally we assign references to the $lists and $page variables so that our layout can access them.

Within our layout default.php file we must make some minor changes toward the end of the existing code. Between the closing </tbody> tag and the </table> tag we must add the following:

<tfoot>
<tr>
<td colspan="10">
<?php echo $this->page->getListFooter(); ?>
</td>
</tr>
</tfoot>

This creates the pagination footer using the JPagination method getListFooter(). The final change we need to make is to add two hidden fields to the form. Under the existing hidden fields we add the following code:

<input type="hidden" name="filter_order"
value="<?php echo $this->lists['order']; ?>" />
<input type="hidden" name="filter_order_Dir" value="" />

The most important thing to notice is that we leave the value of the filter_order_Dir field empty. This is because the listFooter deals with this for us.

Customize backend Component in Joomla! 1.5

That is it! We now have added pagination to our page.

Ordering

Another enhancement that we can add is the ability to sort or order our data by column, which we can accomplish easily using the JHTML grid.sort type. And, as an added bonus, we have already completed a significant amount of the necessary code when we added pagination.

Most of the changes to revues/view.html.php that we made for pagination are used for implementing column ordering; we don't have to make a single change. We also added two hidden fields, filter_order and filter_order_Dir, to our layout form, default.php. The first defines the column to order our data and the latter defines the direction, ascending or descending.

Most of the column headings for our existing layout are currently composed of simple text wrapped in table heading tags (<th>Title</th> for example). We need to replace the text with the output of the grid.sort function for those columns that we wish to be orderable. Here is our new code:

<thead>
<tr>
<th width="20" nowrap="nowrap">
<?php echo JHTML::_('grid.sort', JText::_('ID'), 'id',
$this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
<th width="20" nowrap="nowrap">
<input type="checkbox" name="toggle" value=""
onclick="checkAll(
<?php echo count($this->revues); ?>);" />
</th>

<th width="40%">
<?php echo JHTML::_('grid.sort', JText::_('TITLE'),
'title', $this->lists['order_Dir'],
$this->lists['order'] ); ?>

</th>
<th width="20%">
<?php echo JHTML::_('grid.sort', JText::_('REVUER'),
'revuer', $this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
<th width="80" nowrap="nowrap">
<?php echo JHTML::_('grid.sort', JText::_('REVUED'),
'revued', $this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
<th width="80" nowrap="nowrap" align="center">
<?php echo JHTML::_('grid.sort', 'ORDER', 'ordering',
$this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
<th width="10" nowrap="nowrap">
<?php if($ordering) echo JHTML::_('grid.order',
$this->revues); ?>
</th>
<th width="50" nowrap="nowrap">
<?php echo JText::_('HITS'); ?>
</th>
<th width="100" nowrap="nowrap" align="center">
<?php echo JHTML::_('grid.sort', JText::_('CATEGORY'),
'category',
$this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
<th width="60" nowrap="nowrap" align="center">
<?php echo JHTML::_('grid.sort', JText::_('PUBLISHED'),
'published',
$this->lists['order_Dir'],
$this->lists['order'] ); ?>
</th>
</tr>
</thead>

Let's look at the last column, Published, and dissect the call to grid.sort. Following grid.sort we have the name of the column, filtered through JText::_() passing it a key to our translation file. The next parameter is the sort value, the current order direction, and the current column by which the data is ordered.

In order for us to be able to use these headings to order our data we must make a few additional modifications to our JModel class.

We created the _buildQuery() method earlier when we were adding pagination. We now need to make a change to that method to handle ordering:

/**
* Builds a query to get data from #__boxoffice_revues
* @return string SQL query
*/
function _buildQuery()
{
$db =& $this->getDBO();
$rtable = $db->nameQuote('#__boxoffice_revues');
$ctable = $db->nameQuote('#__categories');
$query = ' SELECT r.*, cc.title AS cat_title'
. ' FROM ' . $rtable. ' AS r'
. ' LEFT JOIN '.$ctable.' AS cc ON cc.id=r.catid'
. $this->_buildQueryOrderBy();

return $query;

}

Our method now calls a method named _buildQueryOrderBy() that builds the ORDER BY clause for the query:

/**
* Build the ORDER part of a query
*
* @return string part of an SQL query
*/
function _buildQueryOrderBy()
{
global $mainframe, $option;
// Array of allowable order fields
$orders = array('title', 'revuer', 'revued', 'category',
'published', 'ordering', 'id');

// Get the order field and direction, default order field
// is 'ordering', default direction is ascending
$filter_order = $mainframe->getUserStateFromRequest(
$option.'filter_order', 'filter_order', 'ordering');
$filter_order_Dir = strtoupper(
$mainframe->getUserStateFromRequest(
$option.'filter_order_Dir', 'filter_order_Dir', 'ASC'));

// Validate the order direction, must be ASC or DESC
if ($filter_order_Dir != 'ASC' && $filter_order_Dir != 'DESC')
{
$filter_order_Dir = 'ASC';
}

// If order column is unknown use the default
if (!in_array($filter_order, $orders))
{
$filter_order = 'ordering';
}
$orderby = ' ORDER BY '.$filter_order.' '.$filter_order_Dir;
if ($filter_order != 'ordering')
{
$orderby .= ' , ordering ';
}
// Return the ORDER BY clause

return $orderby;
}

As with the view, we retrieve the order column name and direction using the application getUserStateFromRequest() method. Since this data is going to be used to interact with the database, we perform some data sanity checks to ensure that the data is safe to use with the database.

Now that we have done this we can use the table headings to order itemized data. This is a screenshot of such a table:

Customize backend Component in Joomla! 1.5

Notice that the current ordering is title descending, as denoted by the small arrow to the right of Title.

Mastering Joomla! 1.5 Extension and Framework Development The Professional Guide to Programming Joomla!
Published: November 2007
eBook Price: €20.99
Book Price: €45.99
See more
Select your format and quantity:

(Read more interesting articles on Joomla! 1.5here.)

Filtering and searching

In many respects, the process of filtering and searching itemized data is very similar to ordering itemized data. We'll begin by taking a look at filtering.

This is a screenshot of the filtering and search form controls that appear at the top of the Article Manager:

Customize backend Component in Joomla! 1.5

In this case, there are many filtering options: the section, category, author, and published state. For our component we will look at how to implement a category filter and a published-state filter.

We can use the grid.state type to easily render a published state drop-down selection box. In our /revues/view.html.php file we need to make two modifications:

// Get the user state
$filter_order = $mainframe->getUserStateFromRequest(
$option.'filter_order',
'filter_order', 'published');
$filter_order_Dir = $mainframe->getUserStateFromRequest(
$option.'filter_order_Dir',
'filter_order_Dir', 'ASC');
$filter_state = $mainframe->getUserStateFromRequest(
$option.'filter_state', 'filter_state');

// set the table filter values
$lists['order'] = $filter_order;
$lists['order_Dir'] = $filter_order_Dir;

We use the application getUserStateFromRequest() method to determine the current published state filter value, using the path $option plus filter_state.The default value is a null string, which indicates that no selection has been made.

Once we have the published state filter value, we use the grid.state type to render a drop-down list form control with the available published state properties. This control has some JavaScript associated with it that automatically submits the form when the JavaScript onChange event is fired.

Now that we have a form control we need to display it. We do this in the default.php layout by placing the following table declaration between the admin form and table declaration:

<table>
<tr>
<td align="left" width="100%"></td>
<td nowrap="nowrap">
<?php echo $this->lists['state']; ?>
</td>
</tr>
</table>

It is normal to use a table with one row and two cells to display filters and search controls. The left-hand cell is used to display the search and the right-hand cell is used to display the filter drop-down selection boxes.

As with most things in Joomla!, there are no strings attached as to how we implement filtering and searching. We don't have to format the filter in this way, and for those of us who prefer a good dose of CSS, it is perfectly acceptable to implement a table-less design.

The next question is: How do we apply a filter? This is far easier than it might sound. When we discussed ordering we described the _buildQuery() method in the model. It's back to that method to make some more changes:

/**
* Builds a query to get data from #__boxoffice_revues
* @return string SQL query
*/
function _buildQuery()
{
$db =& $this->getDBO();
$rtable = $db->nameQuote('#__boxoffice_revues');
$ctable = $db->nameQuote('#__categories');
$query = ' SELECT r.*, cc.title AS cat_title'
. ' FROM ' . $rtable. ' AS r'
. ' LEFT JOIN '.$ctable.' AS cc ON cc.id=r.catid'
. $this->_buildQueryWhere()
. $this->_buildQueryOrderBy();

return $query;
}

This time we have added a call to a private _buildQueryWhere() method. This method works in much the same way as the _buildQueryOrderBy() method, except that it returns a WHERE clause instead of an ORDER BY clause.

This example demonstrates how we can implement this method in order to apply the published state filter:

/**
* Builds the WHERE part of a query
*
* @return string Part of an SQL query
*/
function _buildQueryWhere()
{
global $mainframe, $option;
// Get the filter values
$filter_state = $mainframe->getUserStateFromRequest(
$option,'filter_state','filter_state');

// Prepare the WHERE clause
$where = array();

// Determine published state
if ( $filter_state == 'P' )
{
$where[] = 'published = 1';
}
elseif($filter_state == 'U')
{
$where[] = 'published = 0';
}

// return the WHERE clause
return ($where) ? ' WHERE '.$where : '';
}

The first thing we do is retrieve the published state value from the user state. This will be one of four values: null, P, U, or A. null means 'any'. P and U relate to 'published' and 'unpublished' respectively. A means 'archived'.

Use of the archived published state is unusual. Archived refers to items that are no longer in use and aren't to be modified or viewed in any form. If we want to use archive as a published state, we would have to modify our use of grid.state.

We then build our WHERE clause and return the result. When we create a method such as this, it is important to remember that any external data we use is sanitized and escaped for use with the database.

This now means that we can implement and use a published state filter. Let's go to the next stage, adding the ability to filter by a category. Unsurprisingly, we start in much the same place, the view's display method.

This example builds on the previous example and adds a category filter drop-down selection box:

// Force the layout form to submit itself immediately
$js = 'onchange="document.adminForm.submit();"';

// Get the user state
$filter_order = $mainframe->getUserStateFromRequest(
$option.'filter_order',
'filter_order', 'published');
$filter_order_Dir = $mainframe->getUserStateFromRequest(
$option.'filter_order_Dir',
'filter_order_Dir', 'ASC');
$filter_state = $mainframe->getUserStateFromRequest(
$option.'filter_state', 'filter_state');
$filter_catid = $mainframe->getUserStateFromRequest(
$option.'filter_catid', 'filter_catid');

// set the table filter values
$lists['order'] = $filter_order;
$lists['order_Dir'] = $filter_order_Dir;
$lists['state'] = JHTML::_('grid.state', $filter_state);
$lists['catid'] = JHTML::_('list.category',
'filter_catid',
'com_boxoffice',
(int)$filter_catid, $js);

This time we also retrieve the current value for filter_catid; there are no restrictions on what we call filter form controls, but it is normal to prefix them with filter_. Instead of using grid, we use a list type, list.category, to render the category filter form control.

Unlike grid.state, we must tell list.category the name of the control, the extension name (category section), and the current category. Note that we cast the value of $filter_catid to an integer for security reasons. Last of all, we include some JavaScript.

This JavaScript forces the adminForm form to submit itself, applying the filter immediately. The first entry in the resultant drop-down list is Select a Category. We can opt to make our JavaScript slightly more intelligent by not submitting the form if the Select a Category option is chosen, as this JavaScript demonstrates:

$js = "onchange=\"if (this.options[selectedIndex].value!='')

{ document.adminForm.submit(); }\"";

Now in our default.php layout we add the lists['catid'] value to the table above the itemized data:

<table>
<tr>
<td align="left" width="100%"></td>
<td nowrap="nowrap">
<?php echo $this->lists['catid']; ?>
<?php echo $this->lists['state']; ?>
</td>
</tr>
</table>

The final stage is to apply the category filter to the itemized data. We do this in much the same way as we modified the results for the published state filter. This example shows how we can modify the JModel _buildQueryWhere() method to incorporate the category:

/**
* Builds the WHERE part of a query
*
* @return string Part of an SQL query
*/
function _buildQueryWhere()
{
global $mainframe, $option;
// Get the filter values
$filter_state = $mainframe->getUserStateFromRequest(
$option.'filter_state', 'filter_state');

// Prepare the WHERE clause
$where = array();

// Determine published state
if ( $filter_state == 'P' )
{
$where[] = 'published = 1';
}
elseif($filter_state == 'U')
{
$where[] = 'published = 0';
}

// Determine category ID
if ($filter_catid = (int)$filter_catid)
{
$where[] = 'catid = '.$filter_catid;
}

// return the WHERE clause
return (count($where)) ? ' WHERE '.implode(' AND ', $where)
: '';
}

To facilitate the easiest way of building the WHERE clause we make $where an array and implode it at the end. Note that we cast $filter_catid to an integer; this ensures the value is safe for use with the database.

Before we move on to explain how to implement a search filter, we will quickly discuss the use of other filters.

So far we have demonstrated how to use grid.state and list.category. There are many other things on which we might want to filter itemized data. Some of these are easily available through the list types, for example list.positions.

If there isn't a suitable list type, we can construct our own filter drop-down selection boxes using the select types. This is an example of how we might construct a custom drop-down selection filter form control (it assumes $js is the same as in the previous examples):

// prepare database
$db =& JFactory::getDBO();
$query = 'SELECT value, text' .
'FROM #__sometable' .
'ORDER BY ordering';
$db->setQuery($query);

// add first 'select' option
$options = array()
$options[] = JHTML::_('select.option', '0', '- '
. JText::_('Select a Custom Thing').' -');

// append database results
$options = array_merge($options, $db->loadObjectList());

// build form control
$lists['custom'] = JHTML::_('select.genericlist',
$options,
'filter_custom',
'class="inputbox" size="1"'.$js,
'value',
'text',
$filter_custom);

If we do create custom filter lists such as this, we might want to consider extending JHTML. For example to create a foobar group type we would create a class named JHTMLFoobar in a file named foobar.php. We would then need to use the JHTML::addIncludePath() method to point to the folder where the file is located.

To use the new class we would need to define methods within the class, for example baz(). We would then be able to call baz() using JHTML::_('foobar.baz'). For examples of existing classes we can browse the joomla.html library files.

Next up is searching. This functionality may sound more complex, but in reality it is relatively simple. As with filtering, ordering, and pagination we must make a few modifications to our display method in our /revues/view.html.php file. Building on our previous modifications we modify the display method as follows:

// Force the layout form to submit itself immediately
$js = "onchange=\"if (this.options[
selectedIndex].value!='')
{ document.adminForm.submit(); }\"";

// Get the user state
$filter_order = $mainframe->getUserStateFromRequest(
$option.'filter_order',
'filter_order', 'published');
$filter_order_Dir = $mainframe->getUserStateFromRequest(
$option.'filter_order_Dir',
'filter_order_Dir', 'ASC');
$filter_state = $mainframe->getUserStateFromRequest(
$option.'filter_state', 'filter_state');
$filter_catid = $mainframe->getUserStateFromRequest(
$option.'filter_catid', 'filter_catid');
$filter_search = $mainframe->getUserStateFromRequest(
$option.'filter_search',
'filter_search');

// Build the list array for use in the layout
$lists['order'] = $filter_order;
$lists['order_Dir'] = $filter_order_Dir;
$lists['state'] = JHTML::_('grid.state', $filter_state);
$lists['catid'] = JHTML::_('list.category',
'filter_catid',
'com_boxoffice',
(int)$filter_catid, $js);
$lists['search'] = $filter_search;

Now in our default.php layout we add the following code to the first cell in the table above the itemized data:

<table>
<tr>
<td align="left" width="100%">
<?php echo JText::_('Filter'); ?>:
<input type="text" name="filter_search" id="search"
value="<?php echo $this->lists['search'];?>"
class="text_area"
onchange="document.adminForm.submit();" />
<button onclick="this.form.submit();">
<?php echo JText::_('Search'); ?>
</button>
<button onclick="document.adminForm.
filter_search.value='';this.form.submit();">
<?php echo JText::_('Reset'); ?>
</button>
</td>
<td nowrap="nowrap">
<?php echo $this->lists['catid']; ?>
<?php echo $this->lists['state']; ?>
</td>
</tr>
</table>

As you can see, this is more complex than displaying the previous filter form controls. We output the text Filter and add three form controls—a search text box called filter_search, a reset button, and a search button.

The text box is used to allow the user to define the search terms. The search button submits the form. The reset button sets the search text box value to a null string and then submits the form.

That's it! Now all we need to do is implement the search in the JModel. To do this, we modify the _buildQueryWhere() method:

/**
* Builds the WHERE part of a query
*
* @return string Part of an SQL query
*/
function _buildQueryWhere()
{
global $mainframe, $option;

// Get the filter values
$filter_state = $mainframe->getUserStateFromRequest(
$option.'filter_state', 'filter_state');

// Prepare the WHERE clause
$where = array();

// Determine published state
if ( $filter_state == 'P' )
{
$where[] = 'published = 1';
}
elseif($filter_state == 'U')
{
$where[] = 'published = 0';
}

// Determine category ID
if ($filter_catid = (int)$filter_catid)
{
$where[] = 'catid = '.$filter_catid;
}

// Determine search terms
if ($filter_search = trim($filter_search))
{
$filter_search = JString::strtolower($filter_search);
$db =& $this->_db;
$filter_search = $db->getEscaped($filter_search);
$where[] = '(LOWER(title) LIKE "%'.$filter_search.'%"'
. ' OR LOWER(revuer) LIKE "%'.$filter_search.'%")';
}

// return the WHERE clause
return (count($where)) ? ' WHERE '.implode(' AND ', $where)
: '';
}

We use the JDatabase object to escape the search string; this prevents SQL injection and corruption of the query.

Our search facility will now work!

Summary

We discovered how to add pagination, ordering, filtering, and searching to make our extensions more user-friendly and increase the chances of having successfully created a commercially winning or freely available extension.


If you have read this article you may be interested to view:

Mastering Joomla! 1.5 Extension and Framework Development The Professional Guide to Programming Joomla!
Published: November 2007
eBook Price: €20.99
Book Price: €45.99
See more
Select your format and quantity:

About the Author :


Chuck Lanham

Chuck Lanham began his career as a database software engineer with Burroughs Corp. He later worked for Informix Corp. managing the database tools development group while serving as repository architect. He has founded and managed two successful software development companies, and taught college courses on database theory, data communications, and computer technologies. He has also managed the global development and deployment of leading CRM and CMS systems for many Fortune 500 companies, and managed the development and deployment of some of the largest e-commerce websites in the world.

In 2002, Chuck left the corporate world and started a new company, Blue Water Associates. This company is located near the deep blue waters of Lake Tahoe where he designs, develops, and maintains websites for small to medium sized businesses, both within the U.S. and abroad.

Chuck has been developing websites using Joomla! since 2007 with the release of version 1.5 and has developed several extensions for use in the websites he has designed. This is Chuck's first book as an author, although he has reviewed and edited several books and written numerous technical articles for publication.

James Kennard

James Kennard is a computer programmer. He has worked with various PHP and MySQL applications, since 2002. He quickly discovered Mambo/Joomla! because of its flexible extension manager. James currently maintains one open-source Joomla! component, which has been translated into over fifteen languages. Moreover, he has plans to build two more open-source components. Examples of his work can be found on his personal website www.webamoeba.co.uk.

Books From Packt


Joomla! 1.5 SEO
Joomla! 1.5 SEO

Joomla! 1.5: Beginner's Guide
Joomla! 1.5: Beginner's Guide

Joomla! E-Commerce with VirtueMart
Joomla! E-Commerce with VirtueMart

Joomla! 1.5 Multimedia
Joomla! 1.5 Multimedia

Joomla! 1.5 Content Administration
Joomla! 1.5 Content Administration

Learning Joomla! 1.5 Extension Development
Learning Joomla! 1.5 Extension Development

Joomla! with Flash
Joomla! with Flash

Joomla! Web Security
Joomla! Web Security


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software