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.
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
)));
}
?>
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:
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.
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:


Nice tutorial this will help me learn symfony, i am a cakephp develloper, but i want to learn more MVC frameworks like ZF too
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!
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
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.
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
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
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.
wszystko już działa, świetny blog będę go śledził na bieżąco.
Pozdrawiam
nie dotykam tej biblioteki ze względu na licencje. Powiedz mi czy stosujesz ja tez do komercyjnych projektów?
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
Please, keep up the excellent work and continue to post topics like this. I am really fan of your site.
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
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
Thanks a lot for this very clear example.
The json_encode and pagination parts were very usefull to me.
Thanks again.
Greetings, I read all your writings, keep them coming.
Super artykul, dzieki!
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.
Give me more details. What kind of problem have you got? Did you check it with Firebug?
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.