This is the documentation for LemonStand V1, which has been discontinued. You can learn more and upgrade your store here.

LemonStand Version 1 Has Been Discontinued

This documentation is for LemonStand Version 1. LemonStand is now offered as a cloud-based eCommerce platform.
You can try the new LemonStand and learn about upgrading here.

List Filters

LemonStand programming framework allows to bind any number of filters to a list. Filters are presented with a special user interface on a page and allow to limit the list content by specific record parameters. For example, filters on the Order List page allow to limit the order list by order status, coupon code, products ordered and some other parameters.

The filters user interface has two elements - the filter panel, which is usually placed above a list, and the filter configuration popup form. The filter panel on the Order List page:

The Current Order Status filter configuration form:

In this section we will continue extending a simple blog module which we started in the Developing a simple module article. In the previous article we created a blog post list. In this article we will demonstrate how you can add a filter for limiting the post list by specific categories.

Developing the filter class

Filters are presented with special classes. We need to develop a class for the category filter. Filter class names, as any other module class names, should follow the naming convention described in the Developing LemonStand modules article. There are no other special requirements for filter class names, but we recommend to add the "_filter" suffix to filter class names in order to distinguish filter classes from other classes.

A suitable name for our category filter class is AbcBlog_Category_Filter. This class should be defined in the modules/abcblog/classes/abcblog_category_filter.php script. Filter classes should extend the Db_DataFilter class. A simplest filter class can contain only the single method - applyToModel(). This method receives a model object and a list of selected primary key values, corresponding records selected by a user in the filter configuration popup form. The method should use the where() method of a passed model object in order to limit the result data set. Here is a full code of the category filter class:

<?
  class AbcBlog_Category_Filter extends Db_DataFilter
  {
    public $model_class_name = 'AbcBlog_Category';
    public $list_columns = array('name');

    public function applyToModel($model, $keys, $context = null)
    {
      $model->where('(
        select 
          count(*) 
        from 
          abcblog_posts_categories 
        where 
          category_id in (?) and 
          post_id=abcblog_posts.id) > 0', 
      array($keys));
    }
  }
?>

The class declaration has two fields: $model_class_name and $list_columns. The $model_class_name field specifies which data model class represents an entity we are going to filter records by. In our case we are going to filter the post list by categories. Categories are presented by the AbcBlog_Category class, and therefore we specified this class name in the $model_class_name field. The $list_columns fields specifies which columns of the filtering data model should be visible in the filter configuration popup form. We want to display only the category name column. The category name is presented with the name column in the database abcblog_categories table.

The applyToModel() method is complicated a bit in our case, because posts and categories are connected using the many-to-many relation and we need to use a subquery in order to find whether a blog post belongs to specific categories. If the category_id field belonged to the abcblog_posts table, the filtering query would be much simpler:

public function applyToModel($model, $keys, $context = null)
{
  $model->where('category_id in (?)', array($keys));
}

But in our case we need to refer to the join table (abcblog_posts_categories) and build a subquery.

The $model variable which is passed to the method is an object of the AbcBlog_Post class (in this specific case). The where() method we use in the code example is a feature of the Active Record engine, which allows to add conditions to the WHERE clause of a resulting SQL query. The first parameter is required - the condition SQL string. The string can contain the question mark, which represents a parameter placeholder. Its value should be passed using the second method parameter. You can find more details about the Db_ActiveRecord class in the Class Reference.

The $keys parameter contains a list of identifiers corresponding filter records selected by a the user. In our case the keys parameter contains a list of category identifiers.

Defining fields in the categories model

Our filter configuration popup form will contain a list of categories. We need to define list columns in the AbcBlog_Category class, in the same way as we did it for the AbcBlog_Post class in the previous article. Below is the full code of the AbcBlog_Category class after adding the column definition code:

<?
  class AbcBlog_Category extends Db_ActiveRecord
  {
    public $table_name = 'abcblog_categories';
    
    public function define_columns($context = null)
    {
      $this->define_column('name', 'Name');
    }
  }
?>

Updating the posts controller and view

Now, when we have the filter class defined, we can extend the blog posts controller and add the filtering features to it. The filtering features are implemented in the Db_FilterBehavior behavior. Also, the Db_FormBehavior behavior, which provides form features, is required for the filter behavior. We need to add both behaviors to the $implement filed of the controller class:

class AbcBlog_Posts extends Backend_Controller
{
  public $implement = 'Db_ListBehavior, Db_FilterBehavior, Db_FormBehavior';
  ...

The filter behavior interacts (and uses) with the list behavior, and we need to define two more list parameters in the controller class:

public $list_options = array();
public $list_custom_prepare_func = null;

These parameters have default values, but they must be defined in the controller in order the filter behavior to be able to configure the list behavior for its own needs.

Also, we need to define the filter configuration fields:

public $filter_list_title = 'Filter posts';
public $filter_onApply = 'listReload();';
public $filter_onRemove = 'listReload();';
public $filter_filters = array(
  'category'=>array(
    'name'=>'Category', 
    'class_name'=>'AbcBlog_Category_Filter', 
    'prompt'=>'Please choose post categories you want to include to the list. Posts with other categories will be hidden.', 
    'added_list_title'=>'Added Categories')
);

The $filter_list_title field sets a title for the filters panel. The $filter_onApply and $filter_onRemove fields contain JavaScript code which will be executed when a user applies or removes a filter. The listReload() JavaScript function is added by the list behavior and it is always available on pages containing a list.

The $filter_filters field contains a list (array) of filters available on the page. Each element of this array should have a unique index ('category' in our case) and contain a list of filter configuration options:

  • name - a filter name to display on the filter panel.
  • class_name - a filter class name.
  • prompt - a message to display above a list of available filter records in the filter configuration popup form.
  • added_list_title - a title to display above the list of selected filter records.

The filter behavior does not limit list records automatically, because in some cases you may want to apply extra conditions to a list content. The list behavior contains the listPrepareData() which could be overridden in the controller class. This method must return a pre-configured model object and thus allows to apply filtering conditions to the model object. In the blog posts controller we implemented the method in the following way:

public function listPrepareData()
{
  $obj = new AbcBlog_Post();
  $this->filterApplyToModel($obj);

  return $obj;
}

The method creates an instance of the AbcBlog_Post class and applies filters to it using the filterApplyToModel() controller's method. This method is added to the controller class by the filter behavior. After that the method returns the pre-configured model object.

Finally we need to update the post list view document (index.htm). The view document contains the listRender() method call. By default the list behavior does not display the filter panel. We need to use the list_render_filters parameter in order to force the behavior to render the filters:

<?= $this->listRender(array('list_render_filters'=>true)) ?>

Now our post list contains the filter panel:

If you click the category link, the filter configuration form will popup. The form contains a list of existing category records:

You can download the updated blog module here.

Next: Forms
Previous: Lists
Return to Lists and Forms in the Administration Area