Symfony 1.4 and ExtJS - displaying data in GridPanel [english]

Now when Symfony 1.4 and Dcotrine 1.2 time has come, i want to show you how easily we can use them with JavaScript framework ExtJs 3.0 - which is typically used to build advanced user interfaces. More information about that amazing library can be found on the main project website. In this post I would like to demonstrate the capabilities of one of the components of this powerful framework - GridPanel. I will use most of the code presented in the previous entry, however, it will be updated to work correctly with the latest Symfony version.

Configuration

The necessary configuration for the tutorial:

  • any server with PHP support at least version 5.2.4 + MySql database;
  • Symfony framework installed version 1.4.X (latest stable Symfony version is always recommended);
  • access to the command line;

At the begining

After setting up the environment we need to create a new Symfony project, generate frontend application (if you use the sandbox is already generated) and a sample module, eg grid.
To do so in the project directory from the command line should be performed sequentially:


symfony generate:project sfExtTest

symfony generate:app frontend

symfony generate:module frontend grid

Connection to the database and test data
For our simple example, we could use static data created in JavaScript, howewer, i would like to show the flow of data between the client application, server and database (ExtJs - Symfony - MySql), so additional configuration is required.

You must configure the connection to database, create tables and load test data. The fallowing code is responsible for the above items (almost the same data have been used previously in this tutorial).

Configuring a database connection:


symfony configure:database mysql:host=localhost;dbname=your_db_name user pass

The structure of the test table:


country:
  actAs: [timestampable]
  columns:
    name:         string(50)
    description:  string(255)
    population:   integer(4)

Test data:


Country:
  Country_:
    name: 'Poland'
    description: 'Description for Poland'
    population: 38130302
  Country_2:
    name: 'Germany'
    description: 'Description for Germany'
    population: 82060000
  Country_3:
    name: 'Brazil'
    description: 'Description for Brazil'
    population: 192098152
  Country_4:
    name: 'USA'
    description: 'Description for USA'
    population: 308147000
  Country_5:
    name: 'Ireland'
    description: 'Description for Ireland'
    population: 6300000
  Country_6:
    name: 'Canada'
    description: 'Description for Canada'
    population: 33874000
  Country_7:
    name: 'India'
    description: 'Description for India'
    population: 1198003000
  Country_8:
    name: 'Italy'
    description: 'Description for Italy'
    population: 60200060
  Country_9:
    name: 'Spain'
    description: 'Description for Spain'
    population: 46661950
  Country_10:
    name: 'Portugal'
    description: 'Description for Portugal'
    population: 10707924
  Country_11:
    name: 'Argentina'
    description: 'Description for Argentina'
    population: 40482000
  Country_12:
    name: 'Estonia'
    description: 'Description for Estonia'
    population: 1340415
  Country_13:
    name: 'Bulgaria'
    description: 'Description for Bulgaria'
    population: 7606551
  Country_14:
    name: 'France'
    description: 'Description for France'
    population: 65073482
  Country_15:
    name: 'Belgium'
    description: 'Description for Belgium'
    population: 10665867
  Country_16:
    name: 'Austria'
    description: 'Description for Austria'
    population: 8356707
  Country_17:
    name: 'Australia'
    description: 'Description for Australia'
    population: 22076000
  Country_18:
    name: 'Japan'
    description: 'Description for Japan'
    population: 127590000
  Country_19:
    name: 'Russia'
    description: 'Description for Russia'
    population: 141909279
  Country_20:
    name: 'Slovakia'
    description: 'Description for Slovakia'
    population: 5379455
  Country_21:
    name: 'Ukraine'
    description: 'Description for Ukraine'
    population: 46011300

Now we need to run from command line sequentially:


  symfony doctrine:build --sql
  symfony doctrine:build --model
  symfony doctrine:build --db
  symfony doctrine:data-load

ExtJS
Next step is to download the latest version (3,0) of ExtJs library from the project official website and unpack it to js/ext directory.

At this point we make changes to the configuration file: view.yml, so that the framework automatically attached the appropriate library js and css (changes should be made to the file: app/frontend/config/view.yml):


  stylesheets:
    - ../js/ext/resources/css/ext-all.css

  javascripts:
    - ext/adapter/ext/ext-base-debug.js
    - ext/ext-all-debug.js

It’s recommended to organize JavaScript code in separate JS file, but in this case, the code responsible for displaying the grid put in the index action view grid module.

Please remember to remove the following code: $this->forward(’default’, ‘module’); from the actions.class.php file.

To be able to begin to work with the grid component we need to know at least the basis of its architecture and components. GridPanel essentially consists of 4 items:

  • Store - object responsible for data storing, including communication with server - in our case JsonStore;
  • Column model - display configuration for each column (such as rendering options);
  • View - special display settings;
  • Selection model - optional component, is responsible for operations on columns (onClick, onSelect, onBeforeSelect) - i wiil try to show the use of this comopnent in a separate entry;

To display the basic version of the grid we need the data, the configuration of columns that we want to display and configuration of the view (grid also accepts additional configuration options that are described in detail in the documentation).

The following code is responsible for all the above elements (file: apps/frontend/modules/grid/templates/indexSuccess.php):


<div id="grid-example"> </div>

<script type="text/javascript">

Ext.onReady(function() {

	// component responsible for connection to the server
	var store = new Ext.data.JsonStore({
		root: 'result',
		totalProperty: 'total', // total number of data
		idProperty: 'id',
		id: 'id',
		remoteSort: true,  // server-side sorting
		fields: ['id', 'name', 'description', 'population', 'created_at'],  // field structure
		url: 'grid/list',
		autoLoad: true  // autoloading
	});

	//columns structure
	var columns = [
		{id:'name',header: 'Country', width: 160, sortable: true, dataIndex: 'name'},
		{header: 'Description', width: 160, sortable: false, dataIndex: 'description'},
		{header: 'Population', width: 160, sortable: true, dataIndex: 'population'},
		{header: 'Created at', width: 100, sortable: true, dataIndex: 'created_at'}
	];

	// gridPanel object
	var grid = new Ext.grid.GridPanel({
		title: 'Symfony 1.2 and Ext.js example',
		loadMask: true,   // mask panel when data is loading
		store: store,
		columns: columns,
		autoExpandColumn: 'name',
		height: 400,
		width: 600,
		renderTo: 'grid-example'  // DOM element
	});

});

</script>

To component can work properly we need to create additional action: “list” - for data processing (file: apps/frontend/modules/grid/actions/actions.class.php):


<?php

  public function executeList(sfWebRequest $request) {

	# some static data
	$limit = 15;
	$page = 1;

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

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

	$result = array();

	foreach($pager->getResults() as $country) {

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

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

?>

JSON (JavaScript Object Notation) is a data format used in applications based on the extjs framework. Access to data in JSON format is easier and faster with JavaScript than the level of access to the same data in XML format

At this point you can test the code: http://localhost/application-name/web/grid

We should see a grid similar to that shown in the figure below:

Sample grid

Support for paging and sorting
The current figure of the grid is quite inconvenient, displaying a couple of records on one list it not a problem, but when the database starts to grow, loading all the data and manipulate them, it becomes almost impossible.

PagingToolbar is a component responsible for paging on the ExtJs side. Its key element was defined earlier: store component. Responsible for the paging code is shown below:


var paging = new Ext.PagingToolbar({
	pageSize: 10,  // items per page
	store: store,
	displayInfo: true,
	displayMsg: 'Displaying countries {0} - {1} of {2}',   // messages
	emptyMsg: 'Country list is empty'
});

/ / small modification of the grid code
var grid = new Ext.grid.GridPanel({
	...
	bbar: paging,   // set the bottom panel
	...
});

To paging and sorting work properly, action “list” (in which we build the appropriate query based on request parameters) requires some modifications.

Each call to action in the grid causes a new request is created with the parameters: dir (sort direction ASC/DESC), limit, sort (name of the field), start (offset)

ExecuteList action, also requires modification - we need to add paging support and sorting by the selected column:


<?php

  public function executeList(sfWebRequest $request) {

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

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

	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 query
	$pager->setQuery($query);
	$pager->setPage($page);
	$pager->init();

	$result = array();

	foreach($pager->getResults() as $country) {

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

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

?>

Now we only need to refresh the page and verify that all changes have been properly marked - it should looks something like this:

Grid panel with paging and sorting

If not all the new items show up correctly it is recommended to clean the cache calling symfony cc command (alias for cache-clear). This type of operation should also be carried out, for example, after generating the classes of models or forms, installing plugins, especially when we change the configuration files that are stored in files with YML.

21 Responses to “Symfony 1.4 and ExtJS - displaying data in GridPanel [english]”


  1. 1 Gamer

    Nice tutorial this will help me learn symfony, i am a cakephp develloper, but i want to learn more MVC frameworks like ZF too :)

  2. 2 Kamil

    Siema. PorzÄ…dny tutorial Kamilu. Ja na razie studiujÄ™ symfonowy kurs “Jobeet” ale zaraz po tym chyba wezmÄ™ siÄ™ za Ext 3, wiÄ™c powyższy tutek jak najbardziej mi siÄ™ przyda;-)
    PS. A można skrypt generujący Grida wrzucić do jakiejś metoty i tylko ją wywołać gdy element zostanie utworzony..? Lubię mieć w kodzie HTML jak najmniej kodu z innej beczki;-)
    Pozdrawiam!

  3. 3 Kamil Adryjanek

    W kolejce czeka jeszcze kilka tutoriali dotyczÄ…cych Ext.js i Symfony, ale mam ostatnio ogromne problemy z wolnym czasem.
    Co do kodu JS - tak jak napisałem, zalecane jest przechowywanie go w osobnych plikach, jednakże w tym wypadku nie było konieczne. W przypadku dużych aplikacji warto z góry ustalić strukturę plików - warto przeczytać: http://www.extjs.com/learn/Tutorial:Writing_a_Big_Application_in_Ext
    Pozdrawiam

  4. 4 Samuel morhaim

    Very nice tutorial, one question… Do you have an example, on saving data back to the DB? If you use the ExtJS table with modification options, it would be nice to be able to save back to the DB.. but I am not sure how to do it.

    Thank you.

  5. 5 Kamil Adryjanek

    There are several ways to achieve this. We can use for example Editable Grid or Row Editor Grid. We can also build some simple form and assign it to grid. I will do my best to show how this can be done in the next entry.

    Cheers

  6. 6 Wojciech

    Bardzo fajne tutoriale!
    Próbuje przerobić ten tutorial na orm:propel.
    Widzę, że w poprzednim tutorialu z Ext zrobiłeś z propelem dla Symfony 1.2. Wydaje mi się, że ten kod executeList() z poprzedniego tutorialu nie działa z tym pod Symfony 1.4.x. Czy gdybyś znalazł czas mógłbyś zrobić ten tutorial pod propela, możesz napisać do mnie na maila.

    Pozdrawiam

  7. 7 Kamil Adryjanek

    Kod z poprzedniego tutoriala powinien działać prawidłowo również z wersją 1.4.X - napisz jakiej wersji Propela używasz i jakie napotkałeś problemy/błędy to spróbuje Ci pomóc.

  8. 8 Wojciech

    wszystko już działa, świetny blog będę go śledził na bieżąco.

    Pozdrawiam

  9. 9 aniolekx

    nie dotykam tej biblioteki ze względu na licencje. Powiedz mi czy stosujesz ja tez do komercyjnych projektów?

  10. 10 Kamil Adryjanek

    Przede wszystkim do komercyjnych projektów. Licencja na jednego programistę kosztuje około 350$, które zwracają się z nawiązką przy pierwszym projekcie.

    Pozdrawiam

  11. 11 Michael Eldridge

    Please, keep up the excellent work and continue to post topics like this. I am really fan of your site.

  12. 12 Wojciech

    a jak z wykorzystaniem biblioteki ExtJS w pracy magisterskiej, czy jest to legalnie możliwe? Aktualnie pisze prace i chciałbym wykorzystać tą bibliotekę.

    Pozdrawiam

  13. 13 Kamil Adryjanek

    Mój znajomy, z powodzeniem wykorzystał Ext JS w swojej pracy magisterskiej. Jeśli dobrze pamiętam napisał przykładową aplikację wykorzystującą możliwości tej właśnie biblioteki - coś w rodzaju Web Desktop. Licencja z tego co się orientuje jest restrykcyjna w przypadku projektów komercyjnych.

    Pozdrawiam

  14. 14 Heidy

    Thanks a lot for this very clear example.
    The json_encode and pagination parts were very usefull to me.
    Thanks again.

  15. 15 Learn Drums

    Greetings, I read all your writings, keep them coming.

  16. 16 Marta

    Super artykul, dzieki!

  17. 17 mohd shakir

    I’m trying it on Symfony 1.4.4 and ExtJS 3.2.1, and the paging doesn’t seem to work. Can anyone confirm it, or it’s just me missing something from the post.

  18. 18 Kamil Adryjanek

    Give me more details. What kind of problem have you got? Did you check it with Firebug?

  19. 19 mohd shakir

    I’m not used to Firebug, so let me just explain my situation here;

    The grid will only display the amount of row as in the $limit (whether I change 10 or limit to any number, it’ll list that particular number of row), as in this code.

    public function executeList(sfWebRequest $request) {

    # data retrieved from the request
    $limit = $request->getParameter(’limit’, 10);
    …………

    The thing is, even though that I have 100 or more row to display, it’ll just display 10 (or any number that I change it to) row, and the paging toolbar will only show 1 page, without the option to go to the next page.

  20. 20 Garden Canopies

    Fantastic information. Wish i could locate more information like this by others! Many thanks!

  21. 21 Justyna

    Super artykul, dzieki!

  1. 1 Symfony 1.2 i ExtJS - wyswietlamy dane w gridzie | Projektant - Programista PHP, Python
  2. 2 Advanced data filtering with Symfony 1.4 and ExtJS 3.2 [english] | Projektant - Programista PHP, Python

Leave a Reply

PodglÄ…d komentarza:




About me:

  • PHP programmer
  • Symfony developer
  • Zend framework developer

Categories: