11 December 2010 ~ 35 Comments

ExtJs, ExtDesigner and Zend Framework

I have been working on a project the last months and would like to share some of the stuff I have done.

Let’s say you are working on the user interface in Ext Designer / Sencha Ext Js, and after a while you find out you have ended up with a great amount of data stores. You also need to handle lots of ajax requests and all the serverside coding this invokes. But, why not think two steps forward already when working with the interface in Ext Designer? Of course, you are an experienced developer – so you have your databasemodel ready. More on that later. Let’s start with the user interface in Ext Designer.

Creating the UI in Ext Designer

So, let’s build the user interface in Ext Designer. If you are unfamiliar with Ext Designer, read my post Ext Designer – tutorial for developers.

Let’s say we want to list all companies in gridpanel, handle a click in the company gridpanel and display all employees in the company in a new gridpanel.
We should end up with something like this:
Ext Designer - Zend Framework, step 1

What I have done here is the following:

  1. Added a panel to wrap up the two grids and give it the jsClass AboutFrontend (or whatever suits you, just remeber).
  2. Added two grid panels, on called Company and the other called Employees (for the records, I also gave them the id’s: companyGrid and employeeGrid. You’ll figure out why later on.)
  3. Set dataIndex and name in each column to match my database model.
  4. For each of the grid panels I have named the stores: tblCompany and tblEmployee.

Do you catch the point already? We have not created any stores in Ext Designer, we have just told the grids that: yes, we have a store for you – and this is it’s name.

Okei. Let’s save the project for now and start coding some php in Zend Framework. I presume you have Zend Framework installed, if not read my quick post about installing Zend Framework from command line.

Setup database

My simple model looks like this:

Databasemodel for my Ext Designer - Zend Framework application

It’s made in MySQL Workbench btw.

Next up, create the database tabels. My simple example is based on a MySQL database and the structure looks like this:

CREATE  TABLE IF NOT EXISTS `tblCompany` (
  `company_id` INT NOT NULL ,
  `name` VARCHAR(45) NOT NULL ,
  PRIMARY KEY (`company_id`) );

CREATE  TABLE IF NOT EXISTS `tblEmployee` (
  `employee_id` INT NOT NULL AUTO_INCREMENT ,
  `company_id` INT NOT NULL ,
  `name` VARCHAR(45) NOT NULL ,
  `email` VARCHAR(45) NOT NULL ,
  PRIMARY KEY (`employee_id`) ,
  CONSTRAINT `fk_tblEmployee_tblCompany`
    FOREIGN KEY (`company_id` )
    REFERENCES `tblCompany` (`company_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

CREATE INDEX `fk_tblEmployee_tblCompany` ON `.`tblEmployee` (`company_id` ASC) ;

Setting up the Zend Framework project

I’ll just briefly show the commands used for setting up and configring the Zend Framework. If you need info about Zend Framework, try googling “Zend Framework getting started“!.

$ zf.sh create project ext-designer-zend-framework-store-trick
$ cd ext-designer-zend-framework-store-trick
$ ls
// lists application, docs, library, public and tests
$ zf.sh configure db-adapter "adapter=PDO_Mysql&username=login&password=password&dbname=dbname"
$ zf.sh create dbtable.from-database

We’ll also create a controller and some actions, for later use:

$ zf.sh create controller Ext
$ zf.sh create action getstore Ext
$ zf.sh create action getdata Ext

So, now we have:
– The user interface
– The database
– The serverside framwork

It’s time for you to start coding? Maybe not. Follow me on.

Introducing the new Zend_Db_Table class: Ext Store

	function convertDataTypeToExtType($type)	{
		$datatypes = array(
			'int'=->'int',
			'varchar'=->'string',
			'text'=->'string',
			'datetime'=->'date',
			'date'=->'date',
			'decimal'=->'float',
			'float'=->'float'
		);
		while(list($k, $v)=each($datatypes))	{
			if($type == $k)	return $v;
		}
		return 'auto';
	}
	
	class ExtStore extends Zend_Db_Table	{
		
		public function getStore($load_data = "false", $store_name = false)	{
			$i = $this->info();
			
			$str  = $this->getHead($i, $load_data, $store_name);
			$str .= $this->getFields($i);
			$str .= $this->getFoot($i, $store_name);
			
			return $str;
			
		}
		
		private function getHead($i, $load_data, $store_name)	{
			$name = $store_name ? $store_name : $i['name'];
			
			return $name."Store = Ext.extend(Ext.data.JsonStore, {
    constructor: function(cfg) {
        cfg = cfg || {};
        ".$name."Store.superclass.constructor.call(this, Ext.apply({
            storeId: '".$name."Store',
            autoLoad: ".$load_data.",
            url: 'index.php/ext/getdata/store/".$i['name']."',
            ";
		}
		
		private function getFields($i)	{
			$ret = "fields: [
			";
			$count = 0;
			while(list($field_name, $meta)=each($i['metadata']))	{
				$count++;
				$ret .= "
                {
                    name: '".$field_name."',
                    type: '".convertDataTypeToExtType($meta['DATA_TYPE'])."'
                    ";
				if(in_array($meta['DATA_TYPE'], array("date", "datetime")))	$ret .= "dateFormat: '.Y-m-d H:i:s'";
				$ret .= "	
                }";	
				if($count-<sizeOf($i['metadata']))	$ret .= ",";
			}
			$ret .= "
            ]";
			return $ret;
		}
		
		private function getFoot($i, $store_name)	{
			$name = $store_name ? $store_name : $i['name'];
			return "            
        }, cfg));
    }
});
new ".$name."Store();";
		}
	}

Let’s walk through this.
The first you see is a simple support function, which you probably should locate elsewhere. The function simply returns known mysql datatypes to known ext store data types. For example, it converts varchar to string.

Next up is the class ExtStore, which extends the Zend_Db_Table class. And, that’s the major point here!

Move on to the getStore method, takes two parameters: $load_data and $store_name, you’ll see the purpose later on. Then, on line 20, you find $i = $this->info(). Remember? This class extends the Zend_Db_Table class, which has an info method. Ref.: http://framework.zend.com/manual/en/zend.db.table.html:
The Zend_Db_Table_Abstract class provides some information about its metadata. The info() method returns an array structure with information about the table, its columns and primary key, and other metadata.

The info() method in the Zend_Db_Table_Abstract gives us information about which columns are available and their datatypes in the specified table.

This is, together with the parameters $load_data and $store_name, passed on to the getHead() method of the class, which returns the head of the Ext Store. If you have an experienced eye, you will probably recognize that the head of the store is pretty much an exact copy&paste from the auto-generated stores from Ext Designer. With some small customizations; setting the name of the store, and the autoLoad parameter.

Next up is the getFields() method, from line 43. By it’s name, I recon you understand the purpose. Exactly! It loops through all columns in the table, and converts them to a string Ext understands. This is also where the convertDataTypeToExtType() function is called.

To finish this up, from line 64 the last method getFoot() finishes out the json syntax, and adds the line:

new ".$name."Store();

which, when the this javascript is executed, creates an instance of the store. And, if load_data is set to true, loads data to the store from our specified url, ajax.php.

Confused? Shall we try it in real life? Okei – keep on reading.

Prepare the Ext controller and view

I recon you have basic knowledge of the Zend Framework MVC, if not – this is not the right article for you.

In the application/controllers folder you will find the ExtController.php. Open it and prepare for some coding in the getstoreAction() method.

class ExtController extends Zend_Controller_Action
{

    public function init()
    {
        /* Initialize action controller here */
    }

    public function indexAction()
    {
        // action body
    }

    public function getstoreAction()
    {
        // action body

        $request = $this->getRequest();
        $store = $request->getParam("store");
        $extstore = new ExtStore($store);
        $this->view->storedefinition = $extstore->getStore(true, $store);

    }

    public function getdataAction()
    {
        // action body

    	$request = $this->getRequest();
        $store = $request->getParam("store");
        $extstore = new ExtStore($store);
        $data = $extstore->fetchAll();
        $this->view->data = $data->toArray();
    }
}

Let’s go through this step by step, starting with the getstoreAction().

First, we need to know a parameter, that is the store name, table name in other words. This will be a parameter you find in the requst. That’s what line 18 & 19 is all about, get the requst object and the the store parameter. Next, you create an instance of the ExtStore class and make the result of getStore() available to the view.

The getstore.phtml is very simple:

storedefinition;
?>

This is nice. Very nice. And very simple.

The getdataAction() is pretty similar. Get the request object, find the table. Then you call the fetchAll() method and make the fetched data available to the view. And, the view getdata.phtml is almost as simple as the getstore.phtml:

data);
?>

All it does is to json encode the result and return it.

Interesting? I guess so, since you are still reading. ๐Ÿ˜‰

Ready to fire up?

Open up the testrun.html file.

<!-- Auto Generated with Ext Designer -->
<!-- Modifications to this file will be overwritten. -->
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>aboutfrontend.com-extdesigner-extjs-zendframework.xds</title>
    <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.2.0/resources/css/ext-all.css"/>
    <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.2.0/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.2.0/ext-all-debug.js"></script>
    <script type="text/javascript" src="js/AboutFrontend.ui.js"></script>
    <script type="text/javascript" src="js/AboutFrontend.js"></script>
    <script type="text/javascript" src="index.php/ext/getstore/store/tblCompany"></script>
    <script type="text/javascript" src="index.php/ext/getstore/store/tblEmployee"></script>
    <script type="text/javascript" src="js/xds_index.js"></script>

</head>
<body></body>
</html>

You should notice line 12-14. That’s where the magic is.

<script type="text/javascript" src="index.php/ext/getstore/store/tblCompany"></script>
    <script type="text/javascript" src="index.php/ext/getstore/store/tblEmployee"></script>
    <script type="text/javascript" src="js/xds_index.js"></script>

First, we need to create the stores. Therefore we call the getstore methods, with the tblCompany and tblEmployee as the store parameter (/store/tblCompany).
Then, and this is important, you include the xds_index.js file. If you include xds_index.js before the stores you will get javascript errors about the stores not beeing defined. Of course.

Apply the click event to the company gridpanel

If you don’t know how to work with projects created with Ext Designer, please read my post Ext Designer – tutorial for a developer.

Since I called my container in Ext Designer AboutFrontend, i open up the file AboutFrontend.js in public/js (export location from Ext Designer, remember?) and modify it to the following:

AboutFrontend = Ext.extend(AboutFrontendUi, {
    initComponent: function() {
        AboutFrontend.superclass.initComponent.call(this);

        this.findById("companyGrid").on("rowclick", function(grid, rowIndex, e) {
        	Ext.StoreMgr.lookup("tblEmployeeStore").filter("company_id", grid.getStore().getAt(rowIndex).get("company_id"));
        });
    }
});

This last part is just for fun actually. The whole concept here is autogenerating Ext JsonStores and populating them with data using Zend Framwork MVC.

My live example looks like this, hopefully yours is about the same? ๐Ÿ™‚

Working example ext designer zend framework before gridpanel clickWorking example ext designer zend framework after gridpanel click

Sample code Ext Designer, ExtJs, Zend Framework

Download zip from here:
http://aboutfrontend.com/examples/extdesigner-extjs-zendframework/extdesigner-extjs-zendframework.zip

That’s pretty much it! I would love to hear your feedback.

Further reading

Zend Studio for Eclipse Developer's Guide
Zend Framework in Action
Beginning PHP RIA Using Extjs

35 Responses to “ExtJs, ExtDesigner and Zend Framework”

  1. angryreader 21 December 2010 at 11:40 Permalink

    Why dont you give whole example in zip file? and why extStore class is unfinished?

  2. maksimer 21 December 2010 at 12:30 Permalink

    Hi angryreader,
    Seems like something happened with the Ext Store class code. It is now updated and complete. Sorry about that.

    I will try to bundle a zip for download tonight, thanks for the tip!

  3. angryreader 21 December 2010 at 12:50 Permalink

    where do i put and include ExtStore class?

  4. maksimer 21 December 2010 at 13:07 Permalink

    I have updated the example in a zip file. Have a look at http://aboutfrontend.com/examples/extdesigner-extjs-zendframework/extdesigner-extjs-zendframework.zip

    Best regards,
    Nils-Fredrik

  5. angryreader 21 December 2010 at 13:07 Permalink

    Thanks for your quick replay and many thanks for this example in the first place. I think we will utilize this approach in our new project. i ll try to spend some time and figure out how to make it work for us. ๐Ÿ™‚

    yet i feel like something doesent add up in this : i call new ExtStore to fetch records from tblEmployee and tblCompany (normaly i would use new tblEmployee (that would maybe extend ExtStore)

    ps. one small correction – i assume it shall be like :
    ..if($count < sizeOf.. or maybe
    …if(($count-1)<sizeOf..
    instead of ..if($count-<sizeOf..

  6. angryreader 21 December 2010 at 13:33 Permalink

    OK! Now everything works just fine. Thanks again for the code and idea. As i said i ll try to expand it for our Zend-Ext solution then will return here with some feedback and maybe some more code. cheers!

  7. maksimer 21 December 2010 at 13:33 Permalink

    Yes, you would have to extend ExtStore to achieve this.

    Thanks for the code correction, will fix that tonight.

    Please keep me posted about how you make progress in the project!

  8. angryreader 21 December 2010 at 15:26 Permalink

    one more quickfix:

    ExtStore class line 54 :
    … $ret .= “,dateFormat: ‘Y-m-d H:i:s'”;
    instead of :
    … $ret .= “dateFormat: ‘.Y-m-d H:i:s'”;

  9. Diego Armando Vargas Salazar 14 April 2011 at 06:05 Permalink

    Hi, first thanks for this sample, i tought it doesn`t work and was a little sad, but an hour later i red the corrections and tomorro at first time at the morning iยดll try it, and iยดm 95% sure of it. thanks for the correction !!

  10. Diego Armando Vargas Salazar 14 April 2011 at 06:06 Permalink

    95% sure tha iยดll work !

  11. Nils-Fredrik 14 April 2011 at 08:05 Permalink

    @Diego Good luck with the retry!

    There is another ExtDesigner and Zend Framework related post you might be interested in: http://aboutfrontend.com/extjs/extjs-combobox-using-extdesigner/

    Keep me updated on how things go.

  12. Diego Armando Vargas Salazar 14 April 2011 at 19:13 Permalink

    Well We downloaded the http://aboutfrontend.com/examples/extdesigner-extjs-zendframework/extdesigner-extjs-zendframework.zip that is updated, we unzip it into our www folder, and edit it with aptana ide, we realize that it doesnt have into configs the application.ini file and We put this:

    [production]
    phpSettings.display_startup_errors = 0
    phpSettings.display_errors = 0
    includePaths.library = APPLICATION_PATH “/../library”
    bootstrap.path = APPLICATION_PATH “/Bootstrap.php”
    bootstrap.class = “Bootstrap”
    appnamespace = “Application”
    resources.frontController.controllerDirectory = APPLICATION_PATH “/controllers”
    resources.frontController.params.displayExceptions = 0
    resources.db.adapter = “PDO_Mysql”
    resources.db.params.host = “localhost”
    resources.db.params.username = “root”
    resources.db.params.password = “koolumbia2011”
    resources.db.params.dbname = “mydb”

    [staging : production]

    [testing : production]
    phpSettings.display_startup_errors = 1
    phpSettings.display_errors = 1

    [development : production]
    phpSettings.display_startup_errors = 1
    phpSettings.display_errors = 1
    resources.frontController.params.displayExceptions = 1

    We realize too that it doesnt have no model, so into model folder we put another folder called DBTable with 2 files: TblCompany.php and TblEmployee.php, generated in an old project when We fallowed this tutorial. Into library folder there is a folder called Zend, we put all the library of zend into it and when we tried it it just shows the first table but empty… can you help us please !!

  13. Nils-Fredrik 15 April 2011 at 07:39 Permalink

    @Diego: Have you read the post “Installing Zend Framework”? http://aboutfrontend.com/zend-framework/installing-zend-framework-on-linux-command-line/

    It sounds to me you don’t have set Zend Framework up properly?

    What happens if you try to run your site through a browser? Do you see the regular ZF frontpage?

  14. Diego Armando Vargas Salazar 15 April 2011 at 18:07 Permalink

    hey thanks it already works !!! yeah… the problem was that i have the project into dropbox/www and the dropbox rename some folders from Zend library… hey thanks a lot

  15. Nils-Fredrik 18 April 2011 at 08:23 Permalink

    @Diego: Great!

  16. Scott Martin 22 May 2011 at 00:50 Permalink

    In downloading your zip for this example, I was unable to get it to run. Are there any files missing from the zip?

    application/config is empty
    application/models is empty

    I copied zend/libraries/Zend/* to your library/Zend dir. (is this required).
    I originally install the entire ZF install to /var/www/zend

    My question is: what steps are exactly needed to make this example run …
    if I download your ZIP and unzip it to /var/www/zftest

    It would also be helpful if you would provide an SQL dump of your data for those that do not have Workbench installed.

    In my case, I am looking at the option to move from CodeIgniter to ZF and I would like a complete example that I can learn from. I have install ZF as explained by your command line install.

    I suspect that a few things are taken for granted in this tutorial and I am starting from scratch.

    Regards,
    Scott.

  17. maksimer 22 May 2011 at 22:08 Permalink

    @ScottMartin

    First, you should have a look at the post: http://aboutfrontend.com/2010/07/installing-zend-framework-on-linux-command-line/ It will explain how to download and install Zend Framework.

    Next is, you should not try to download my example and run it. What I suggest you do is to follow the steps in the tutorial. If you get stuck anywhere, you can have a look at the files in the example and modify your own.

    What plattform are you running? Windows, Linux or Macos?

  18. Gaston Mauger 18 June 2011 at 06:28 Permalink

    Iโ€™m incredibly amazed with your composing skills and with the structure on your weblog. Is it a purchased idea or did you customise it yourself? Both way retain up the great quality writing, it is scarce to see a wonderful weblog prefer that one today.

  19. Florinda Baskerville 22 June 2011 at 05:19 Permalink

    Stumbled across from yahoo, and examine your great submit

  20. Scott Martin 28 July 2011 at 22:31 Permalink

    Nils,

    I use Linux (amd64).

    I was hoping for a ZIP file with a complete working example instead of having to work from blog tutorials. Any chance of this happening?

    Regards,
    Scott.

  21. Maz 25 October 2011 at 11:27 Permalink

    I tested your tutorial, added data to the tables, and launched ../web_root/testrun.html
    But the grids are empty in the test page.

  22. Jim Bell 20 December 2011 at 00:07 Permalink

    Nice to see a website with decent content material these days.

  23. Jim 1 February 2012 at 21:48 Permalink

    I’ve applied some principles using this approach. However, I’ve run into a practical snag with this.

    Consider this example

    Products, Locations, and an maping table to associate which products are at which tables.

    Products
    PROD_ID, Name
    Locations
    LOC_ID, Name
    ProductLocations
    PROD_ID, LOC_ID

    Products – has 20 records
    Locations – has 2000 records
    ProductLocations – has 50,000 records

    This means, using the approach above that the 50,0000 records are retrieved (or a page of them or whatever) until they are filtered.

    To me, that’s not good at all.

    Ideally, I would like to have a list, that can request a sub-list based on a query (not a table!). Showing a loc_id is meaningless to a user, so I would want to show the Location.Name field.

    Dont get me wrong. The approach above saves tons of coding for stores, and models. However, there are instances where that just wont work; and then I am forced into an alternative approach.

    I was considering using Ext.Direct, and mapping my calls from ExtJS to a server-side url.

    Does this make sense? I might not be articulating this very well.

    How have others solved this kind of issue with Ext/Zend?

  24. maksimer 1 February 2012 at 22:25 Permalink

    @Jim, thanks for your comment. As you say, this is not a good approach. Especially if you use it raw like my example.

    I’m a bit short of time now, I am about to finish a large ExtJs4/Zend Framework project. When I have a bit more sparetime I will write some words about what I have done there, to get around exactly the issues you point out here.

    Keywords: Zend Framework MVC, Ext Designer ๐Ÿ™‚

  25. Jim 2 February 2012 at 06:41 Permalink

    I would love to see how others are handling this type of thing.

    Are they having the Zend controllers list out all of the actions, and in essence that becomes the client-side api to access data from the server? This would mean manual store creation on the ExtJS side (and models). If this is the only way to go, then so be it ..

    I just really like the automated model/store approach here; and I have it working for most examples, and created a ExtQuery class to respond similarly to more complex, multi-table join type of stuff.

    I am fairly new to Zend as well as ExtJS, and have a large application that needs to be converted from its legacy codebase; there’s alot to take it thus far; and I cant find practical examples that lead towards best-practices.

    I am not being lazy, I just want to be sure that I am not going to get too far down the “wrong” road ๐Ÿ™‚

  26. Amir Shaheen 12 April 2012 at 08:50 Permalink

    hey i have a problem while integrating zend with extjs am confusing “testrun.html” where to put that file?

  27. asdzv445fxc 12 December 2012 at 16:48 Permalink

    Gratitude is a quality similar to electricity: it must be produced and discharged and used up in order to exist at all.

  28. nuklebon 15 July 2013 at 16:42 Permalink

    First of thanks a lot for the tuto.
    Even thought I downloaad the updated version of the zip, I couldn’t find the ExtStore.php file. Could you help me find it ? Thank in advance.

  29. Nils-Fredrik Winther-Kaland 15 July 2013 at 19:03 Permalink

    Hi Nuklebon,

    The ExtStore.php file is in the .zip file: http://aboutfrontend.com/examples/extdesigner-extjs-zendframework/extdesigner-extjs-zendframework.zip

    It’s located in the library folder.

    Best wishes,

    Nils-Fredrik

  30. nuklebon 16 July 2013 at 10:10 Permalink

    Thanks a lot Nils-Fredrik,
    This tuto has saved me !
    best regards.

  31. Large cracks are a deterrent to potential buyers, and they
    also may be a tripping hazard when you have a parade of interested buyers coming through your home.
    In most cases, people in military services and veterans
    can benefit from extra privileges that allow them to receive a grant without having to
    pay it back. The IRS disputes the deduction, contending that, because the cost relates to entering a new business, it
    should be capitalized.

  32. brownie cupcakes 13 September 2014 at 17:44 Permalink

    Hello there, You have done a fantastic job. I’ll certainly digg it and personally recommend to my
    friends. I am confident they will be benefited from this web site.

  33. Link exchange is nothing else butt it is just
    placing the other person’s webpage link on your page at suitable plac and other
    person will also do similar in favor of you.

    Also visit my web-site sseo Berkhamsated (http://guiltlesscliffh62.wordpress.com)


Leave a Reply