Advanced data filtering with Symfony 1.4 and ExtJS 3.2 [english]

After a couple of weeks I finally found some time to write about Symfony and ExtJS. This time i want to show how to put together to work Symfony 1.4, ExtJS 3.2 and Grid Filter Plugin - for me it’s the one of most powerfull filtering solutions i have ever seen.
Since my last entry about displaying data in ExtJS Grid Panel i have updated Ext library to 3.2 version - they have added some nice features (more information you can find in changelog 3.1 and changelog 3.2) and changed some ExtJs components (more details you will find later).

Configuration and project setup

Information about how to setup new Symfony project and configure it to work well with ExtJS - you can find in this entry - i’m not gonna repeat all steps again. Notice that you should download latest ExtJS version: 3.2 and set up view.yml file to attach neccessary files. You should also load sample data - we need it for our example.

After setting up the environment we can start coding.

In this example i will use a little bit diffrent type of configuration of ExtJS components - this is because next time i would like to show how to add funcionality of creating and updating new records.

ExtJS components

This time i’m going to put all JavaScript code in separate files - it is really good practice for building bigger ExtJS applications than in this example. First i will create grid.js file and put there grid component class and other configuration - i will create my own custom component class: App.country.Grid which inherits from Ext.grid.GridPanel - it’s not really needed now but it will save us time next time. Commnets should help you understand the concept:


// Typical data Store automatically configured with a Ext.data.JsonReader.
var store = new Ext.data.JsonStore({
	// store configs
	url: 'default/list',  // url for retreiving data
    autoLoad: true,
    // reader configs
    totalProperty: 'total',
    successProperty: 'success',  // response status name
    idProperty: 'id',
    root: 'data',
    fields: ['id', 'name', 'description', 'population', 'created_at']
});

// Columns configuration
var columns =  [
    {header: "ID", width: 50, fixed: true, sortable: true, dataIndex: 'id'},
    {header: "Country", width: 50, sortable: true, dataIndex: 'name' },
    {header: "Description", width: 100, sortable: true, dataIndex: 'description' },
    {header: "Population", width: 50, sortable: true, dataIndex: 'population' },
    {header: "Created at", width: 150, fixed:true, sortable: true, dataIndex: 'created_at' }
];

Ext.ns('App', 'App.country');
// my custom grid component
App.country.Grid = Ext.extend(Ext.grid.GridPanel, {

    initComponent : function() {

        // typical viewConfig
        this.viewConfig = {
            forceFit: true,
            emptyText: 'No data found.'
        };

        App.country.Grid.superclass.initComponent.call(this);
    }
});

I think this code do not need additional explanations.

Next step is to create main app.js file - place where i’m going to put my components logic (components initialization) - nothing special so far - simple retrieving data and displaying it in grid. In this example i will place grid into simple window component - for better usability- it’s another good example of using ExtJS components. Code responsible for that:


// when document is ready
Ext.onReady(function() {

	Ext.QuickTips.init();

	// create my custom grid component
    var grid = new App.country.Grid({

        store: store,  // data store for grid
        columns : columns,  //columns configuration
        plugins: [filters],  // additional plugin - Grid Filter Plugin
        bbar: new Ext.PagingToolbar({  //bottom bar configuration
    		pageSize: 15,   // records per page
    		store: store,
    		displayInfo: true
    	})
    });

    // simple window for grid
    var win = new Ext.Window({
        title: 'Advanced data filtering with Grid Filter Plugin',
        height: 410,
        width: 800,
        layout: 'fit',
        items: grid  // just one item
    });

    win.show();  // display window with grid

});

On the server side

There is one more thing to get it to work - we need PHP code on the server side. We can use code from the latest entry or use the following:


  public function executeList(sfWebRequest $request) {

  	 # data retrieved from the request
	$limit = $request->getParameter('limit', 15);
	$page = ($request->getParameter('start', 0)/$limit)+1;
	$dir = $request->getParameter('dir', 'ASC');
	$column = strtolower($request->getParameter('sort', 'name'));

	 # create query object
	$query = Doctrine_Query::create()
		->from('Country c');

	 # conditions for sorting
	if (Doctrine::getTable('Country')->hasColumn($column)) {

		$query->orderBy(sprintf('c.%s %s', Doctrine::getTable('Country')->getFieldName($column), $dir));
	}

	# object responsible for paging
	$pager = new sfDoctrinePager('Country', $limit);

	$pager->setQuery($query);
	$pager->setPage($page);
	$pager->init();

	$result = array();

	 # format result array
	foreach($pager->getResults() as $country) {

		$result[] = $country->toArray();
	}

	# formatted data are returned to the grid
	return $this->renderText(json_encode(array(
		'success'	=> true,
		'total'		=> $pager->getNbResults(),
		'data'		=> $result
	)));
  }

Calling default action of our application we should achieved the following:

Grid Filter plugin

Next step is to apply Grid Filter plugin to our example.

Since ExtJS 3.1 Grid filter plugin has been included in ExtJS package, so it’s not necessary to download any additional code.

I just only copied Filter plugin folder from Ext/examples/ux to Ext/ux for better code organisation. To add all neccessary JS and CSS files we need to edit view.yml file - final version should looks similar to this:


  stylesheets:
    - ../js/ext-3.2.0/resources/css/ext-all.css
    - ../js/ext-3.2.0/ux/gridfilters/css/GridFilters.css
    - ../js/ext-3.2.0/ux/gridfilters/css/RangeMenu.css

  javascripts:
    - ext-3.2.0/adapter/ext/ext-base-debug.js
    - ext-3.2.0/ext-all-debug.js
    - ext-3.2.0/ux/gridfilters/menu/RangeMenu.js
    - ext-3.2.0/ux/gridfilters/menu/ListMenu.js
    - ext-3.2.0/ux/gridfilters/GridFilters.js
    - ext-3.2.0/ux/gridfilters/filter/Filter.js
    - ext-3.2.0/ux/gridfilters/filter/StringFilter.js
    - ext-3.2.0/ux/gridfilters/filter/DateFilter.js
    - ext-3.2.0/ux/gridfilters/filter/ListFilter.js
    - ext-3.2.0/ux/gridfilters/filter/NumericFilter.js
    - ext-3.2.0/ux/gridfilters/filter/BooleanFilter.js
    - grid.js
    - app.js

Now we can configure filter component:


var filters = new Ext.ux.grid.GridFilters({
    local: false,   // enable remote filtering
    filters: [{
        type: 'numeric',  // filter type
        dataIndex: 'id'    // column name
    }, {
        type: 'string',
        dataIndex: 'name'
    }, {
        type: 'string',
        dataIndex: 'description'
    }, {
    	type: 'numeric',
        dataIndex: 'population'
    }, {
        type: 'date',
        dataIndex: 'created_at'
    }]
}); 

And enable it in grid:


    var grid = new App.country.Grid({

        store: store,  // data store for grid
        columns : columns,  //columns configuration
        plugins: [filters],  // additional plugin - Grid Filter Plugin
        bbar: new Ext.PagingToolbar({  //bottom bar configuration
    		pageSize: 15,   // records per page
    		store: store,
    		displayInfo: true
    	})
    });

So filter component could work properly we need to write additional PHP code responsible for filtering data. Using symfony and Doctrine Query Language it is really easy. The fallowing code of action.class.php presents complete code:


  public function executeList(sfWebRequest $request) {

  	 # data retrieved from the request
	$limit = $request->getParameter('limit', 15);
	$page = ($request->getParameter('start', 0)/$limit)+1;
	$dir = $request->getParameter('dir', 'ASC');
	$column = strtolower($request->getParameter('sort', 'name'));

	 # create query object
	$query = Doctrine_Query::create()
		->from('Country c');

	 # conditions for sorting
	if (Doctrine::getTable('Country')->hasColumn($column)) {

		$query->orderBy(sprintf('c.%s %s', Doctrine::getTable('Country')->getFieldName($column), $dir));
	}

	 # code resposible for filtering data
	foreach($request->getParameter('filter') as $filter) {

		 # comparison condition
		if (isset($filter['data']['comparison'])) {

			switch($filter['data']['comparison']) {

				case 'eq':

					$comparison = '=';
					break;

				case 'lt':

					$comparison = '<';
					break;

				case 'gt':

					$comparison = '>';
					break;
			}
		}

		 # switch 5 filter types
		switch($filter['data']['type']) {

			case 'boolean':

				$query->addWhere(sprintf('c.%s = ?', $filter['field']), $filter['data']['value']);

				break;

			case 'string':

				$query->addWhere(sprintf('c.%s LIKE ?', $filter['field']), '%'.$filter['data']['value'].'%');

				break;

			case 'numeric':

				$query->addWhere(sprintf('c.%s %s ?', $filter['field'], $comparison), $filter['data']['value']);

				break;

			case 'list':

				$query->whereIn(sprintf('c.%s', $filter['field']), explode(',', $filter['data']['value'])); 

				break;

			case 'date':

				$query->addWhere(sprintf('c.%s %s ?', $filter['field'], $comparison), date('Y-m-d', strtotime($filter['data']['value'])));

				break;

			default:

				break;
		}
	}

	# object responsible for paging
	$pager = new sfDoctrinePager('Country', $limit);

	$pager->setQuery($query);
	$pager->setPage($page);
	$pager->init();

	$result = array();

	 # format result array
	foreach($pager->getResults() as $country) {

		$result[] = $country->toArray();
	}

	# formatted data are returned to the grid
	return $this->renderText(json_encode(array(
		'success'	=> true,
		'total'		=> $pager->getNbResults(),
		'data'		=> $result
	)));
  }

}

Thats all. As a result we should get:

Enyoj!

2 Responses to “Advanced data filtering with Symfony 1.4 and ExtJS 3.2 [english]”


  1. 1 Arian Maykon de Araújo Diógenes (Dead_Thinker)

    Great post, thanks.

  2. 2 Popadom

    Nicely done!, i can’t wait to see the create and update new records functionality

Leave a Reply

PodglÄ…d komentarza:




About me:

  • PHP programmer
  • Symfony developer
  • Zend framework developer

Categories: