1 Mapping a Grid to a MySQL table using Direct and PHP Part 1
2 ===========================================================
6 In this tutorial we will be looking at how to build a table, or 'grid', that receives its data from a MySQL database. It's aimed at people who have some familiarity with JavaScript, PHP and MySQL but are new to the Ext JS framework. By the end of the tutorial, we'll have a grid component that looks like this:
8 {@img grid-full.png The finished product}
16 * A server with PHP (5.3+) and MySQL (4.1.3+) installed
17 * A browser compatible with Ext JS 4
20 ### 1.2 What is Ext Grid?
21 A grid in Ext JS is "essentially a supercharged `<table>`" to quote [its documentation](#!/api/Ext.grid.Panel). It allows you to manipulate data by sorting and filtering, and to fetch new data in, so it's much more dynamic than your run-of-the-mill table. As you can imagine, this allows you to do some pretty cool things.
23 ### 1.3 What is Ext Direct?
24 Ext Direct provides a way to communicate between the browser and server using less code than traditional methods (i.e. PHP) to actually _do_ stuff with your data.
26 ### 1.4 What's the Benefit of Doing This?
27 There are a number of benefits to using Ext Direct to handle your data:
29 - It's platform agnostic, so it doesn't matter whether you're using PHP, Java or C\# to serve the data.
30 - You can serve _as much_ data as you want, with no negative client-side impacts.
31 - It has [3 types of 'providers'](#!/api/Ext.direct.Manager), that communicate with the server in different ways, we will be using the `RemotingProvider`.
32 - It can bundle your AJAX requests into a single request (by default, all those sent in the first 10ms) and so the server only has to send back one response.
34 Now that we've all been persuaded, lets get to building it.
38 Following the best practices for an Ext application highlighted in the [getting started guide](#/guide/getting_started), we can set up a skeleton directory structure with an index.html file and a blank JavaScript file called grid.js.
45 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
46 <title>List of Velociraptor Owners</title>
48 <link rel="stylesheet" type="text/css" href="resources/css/ext-all.css">
49 <script src="extjs/ext-all-debug.js"></script>
51 <script src="grid.js"></script>
52 <script src="php/api.php"></script>
58 Because we're using the HTML5 document type we're allowed to omit the type in a script tag. It assumes that all `<script>` tags will be JavaScript which helps cut down our bytes. However, you've probably also noticed the peculiar api.php file, surely that can't be JavaScript? All will be explained.
60 Now that the index is pointing to all the right places, unzip your copy of Ext 4 into a folder called 'extjs'. We are now ready to start building the application.
62 IV. Writing the Application
63 ---------------------------
64 We'll start by writing the JavaScript portion to give us something to look at when we start trying to debug the PHP side of the app. Within grid.js we first want to declare what parts of the Ext framework we'll be dealing with, this will probably be a familiar process to ActionScript and Java users but for the rest of us, it's very simple. Because I've seen into the future, I know that we'll be using Ext Direct, Ext Data and Ext Grid, to display the data so we require the following:
74 The asterisk ('`*`') in this context loads all of the classes within those areas of Ext JS, we could optimize it at the end by only requiring the classes that we use. We then want to make a pretty grid to look at, but first, a slight digression.
76 ### 4.1 Models and Stores, An Overview
77 (You can skip this section if you're already familiar with the concept of models and stores)
79 Models and stores are key to presenting users with dynamic data. A 'model' is a blueprint of what a store will look like. Say you have a menu of beers, the model would define what headings to expect, in this case: type (ale, stout, etc.), name, price, and ABV (alcohol by volume). The 'store' will then contain the individual properties, so, Type: 'Ale', Name: 'Jewel', Price: $4.00, ABV: 5.0%. Stores can be represented in many ways and come from many sources but ultimately end up being converted to JSON for use with Ext.
81 ### 4.2 Back to the App
83 To create a model we write the following:
87 Ext.define('PersonalInfo', {
88 extend: 'Ext.data.Model',
89 fields: ['id', 'name', 'address', 'state']
92 What we've done here is give it a name (PersonalInfo), told it that this _extends_ Ext.data.Model, (thankfully we don't need to write all of the necessary code to get a model working, we simply tell it that this extends what the Ext JS framework already provides) and told it what fields (headings) we're going to present to it. All exciting stuff, I'm sure you'll agree.
94 Now, we don't want the JavaScript that renders the grid to initiate before the framework has loaded, this is increasingly important with browsers running JavaScript at near-native speeds. To get around this, we want to use `Ext.onReady`, this will wait for Ext to be fully loaded and the DOM to be fully initialized before we start trying to put our grid on it.
98 Ext.onReady(function() {
100 Ext.create('Ext.grid.Panel', {
102 model: 'PersonalInfo',
115 title: 'Velociraptor Owners',
116 renderTo: Ext.getBody()
120 Once the DOM is ready we use `Ext.create` to make a new grid. A grid requires a store, otherwise it won't have a purpose. We will give it a store that uses the model we defined earlier with the name of 'PersonalInfo' and use the proxy type `direct` to tell it that we'll be using Ext Direct. A proxy tells the application how we'll be communicating with the store. There are many different types which you can find more information [here](#!/api/Ext.data.proxy.Proxy).
122 We then gave the grid a single column (wrapped in an array as we'll be adding more later) with the properties of width and text. The only part that may be unfamiliar here is `dataIndex` - this is what binds the column with the store, so it has to have the same name. After that, everything should be self-explanatory apart from `renderTo: Ext.getBody()`. This is a function that gets the body of the document and will attach the grid to it. Remember that we wrap it all in the `onReady` function? That is so that we don't try to attach it to `<body>` before `<body>` exists.
124 Hopefully, your efforts will be rewarded with this when you refresh the page:
126 {@img grid-bare.png The grid laid bare}
128 ### 4.3 Working with MySQL
129 Now that we have a basic grid working, we'll move on to serving up some data. For our example, we'll be listing everyone that owns a Velociraptor in the USA. You'd expect this to be a fairly small dataset - it's not. [Download and execute this .sql file](guides/direct_grid_pt1/grid-tutorial.sql) and you'll know who to steer clear of. Disclaimer, all of this data has been automatically generated by a dummy data script, any correlations with reality is purely coincidental.
131 If all went well, you should now have a MySQL table populated with 1,000 records which we'll display in our grid.
133 In the root directory of our app, create a folder called `php` followed by another one inside it called `classes`. Within classes create a file called `QueryDatabase.php`.
135 We'll be taking advantage of PHP's MySQLi extension which works with MySQL 4.1.3 and above (any version released after mid-2004 will work fine).
137 First, we'll make a new class and declare some variables:
139 ### `QueryDatabase.php`
150 _Within_ this class, we want to make a function that will connect to the database, (note that you don't write the ..., it's to denote that this block of code continues on from the last one).
152 ### `QueryDatabase.php`
155 public function __construct()
157 $_db = new mysqli('host', 'username' ,'password', 'database');
159 if ($_db->connect_error) {
160 die('Connection Error (' . $_db->connect_errno . ') ' . $_db->connect_error);
166 On line 10, replace 'hostname', 'username', 'password' and 'database' with your own configuration. If this all looks a little alien to you, yet you're used to PHP, it uses a style called 'object-oriented' programming, you can [read more about it online](https://encrypted.google.com/search?q=object+oriented+php). The `->` is called an arrow operator and gets a method (aka a function) from that object. So we're calling the `connect_error` and `connect_errno` functions from the `mysqli` object in this script with the arrow operators.
168 We also want to close the database connection once we're done with it which is simply enough done with:
170 ### `QueryDatabase.php`
173 public function __destruct()
175 $_db = $this->__construct();
181 Notice in the parenthesis we've put `$_db`? This means that this function is going to expect a parameter passed to it, i.e. it's expecting `$_db` otherwise it'll have nothing to close.
183 Now we've got a connection to our database opening and closing we can query it. To do this, we'll create a new function called getResults.
185 ### `QueryDatabase.php`
188 public function getResults($params)
190 $_db = $this->openConnection();
192 $_result = $_db->query("SELECT id, name, address, state FROM owners") or die('Connect Error (' . $_db->connect_errno . ') ' . $_db->connect_error);
196 while ($row = $_result->fetch_assoc()) {
197 array_push($results, $row);
200 $this->closeConnection($_db);
205 That's all for our first PHP file. To recap, we declared some variables at the top of the class and then made 3 functions that will help us as we expand our application. The first function defines the database to use with the credentials needed to access it and fails if it cannot connect (hopefully providing a detailed error message). The second is a simple function that closes the database connection.
207 The third function uses the first function to open a connection and queries the database for all of the records from the fields: 'id', 'name', 'address' and 'state'. We could have used the wildcard operator (`*`) to do the same, but in larger tables you'll probably only want to reveal a subset of fields so it's better to specify them individually. We then push all of the results into a an array called `$results` in a while statement, close the connection to the database once we're done and return the results.
209 ### 4.4 The Complicated Bit
210 Going up a level to the php directory, create a new file called config.php and write the following:
216 'QueryDatabase'=>array(
225 This exposes what methods (functions) are available to our Ext application to call on the server. At the moment, there's only one that we want to reveal, the 'getResults' method we just created. That's all there is to our config.php file for now.
227 To make sure the correct methods are called, we need a router. The router is where the calls from Ext Direct get routed to the correct class using a Remote Procedure Call (RPC).
232 require('config.php');
241 Here, we've declared a class and required our config file that contains which methods we expose in our API.
248 if(isset($HTTP_RAW_POST_DATA)) {
249 header('Content-Type: text/javascript');
250 $data = json_decode($HTTP_RAW_POST_DATA);
251 } else if (isset($_POST['extAction'])) { // form post
253 $isUpload = $_POST['extUpload'] == 'true';
254 $data = new Action();
255 $data->action = $_POST['extAction'];
256 $data->method = $_POST['extMethod'];
257 $data->tid = isset($_POST['extTID']) ? $_POST['extTID'] : null; // not set for upload
258 $data->data = array($_POST, $_FILES);
260 die('Invalid request.');
263 function doRpc($cdata){
266 if(!isset($API[$cdata->action])){
267 throw new Exception('Call to undefined action: ' . $cdata->action);
270 $action = $cdata->action;
273 doAroundCalls($a['before'], $cdata);
275 $method = $cdata->method;
276 $mdef = $a['methods'][$method];
278 throw new Exception("Call to undefined method: $method on action $action");
280 doAroundCalls($mdef['before'], $cdata);
289 require_once("classes/$action.php");
291 if (isset($mdef['len'])) {
292 $params = isset($cdata->data) && is_array($cdata->data) ? $cdata->data : array();
294 $params = array($cdata->data);
297 $r['result'] = call_user_func_array(array($o, $method), $params);
299 doAroundCalls($mdef['after'], $cdata, $r);
300 doAroundCalls($a['after'], $cdata, $r);
303 $r['type'] = 'exception';
304 $r['message'] = $e->getMessage();
305 $r['where'] = $e->getTraceAsString();
310 The doRpc function will provide important information on our data and responses from the server. Basically, if you refresh the page and have a console open you'll see something that looks like this:
312 {@img firebug-post-result.png Sending a request to router.php and getting a response}
314 You can see the results of our $r variable clearly laid out. If you've made an error the result is where the PHP error text will be, but when everything's gone to plan you'll see all of the records that we have added to our database stored as JSON. The PHP that converts it to JSON is:
317 function doAroundCalls(&$fns, &$cdata, &$returnData=null){
323 $f($cdata, $returnData);
326 $fns($cdata, $returnData);
331 if (is_array($data)) {
333 foreach($data as $d){
334 $response[] = doRpc($d);
337 $response = doRpc($data);
339 if ($isForm && $isUpload) {
340 echo '<html><body><textarea>';
341 echo json_encode($response);
342 echo '</textarea></body></html>';
344 echo json_encode($response);
347 Then create a file called 'api.php'. Remember when we pointed our index.html file to a PHP file but told it that it was JavaScript? This is where the magic happens.
352 require('config.php');
353 header('Content-Type: text/javascript');
355 // convert API config to Ext.Direct spec
357 foreach ($API as $aname=>&$a) {
359 foreach ($a['methods'] as $mname=>&$m) {
360 if (isset($m['len'])) {
368 'params'=>$m['params']
371 if (isset($m['formHandler']) && $m['formHandler']) {
372 $md['formHandler'] = true;
376 $actions[$aname] = $methods;
380 'url'=>'php/router.php',
385 echo 'Ext.ns("Ext.app"); Ext.app.REMOTING_API = ';
387 echo json_encode($cfg);
390 The last two files are taken straight from the example in the Ext Direct directory, made by people much smarter than I (hence the sparse comments).
392 It uses the config.php file we made earlier and sets it's header to JavaScript, so any output the browser will expect to be JavaScript. It then proceeds to turn our config and router PHP files into JSON so the right method is called when Ext Direct calls it. Further information can be found on the [Ext Direct specification page](http://www.sencha.com/products/extjs/extdirect).
394 ### 4.5 Get it Together
395 With the hard part now over, the final bits to finish our application are found back in grid.js. We need to tell the proxy what function to call to get the results, tell Ext Direct what type of provider we're using and add the other columns to our grid.
397 To accomplish this, add the following to the relevant parts of grid.js.
401 Ext.onReady(function() {
402 //add a provider to our grid
403 Ext.direct.Manager.addProvider(Ext.app.REMOTING_API);
406 //add directFn to our proxy
409 directFn: QueryDatabase.getResults
412 //add the other columns
422 dataIndex: 'address',
431 We finally tell our application to use the Remoting Provider and `directFn` calls `getResults` as soon as it's run to add our data to the grid.
433 The columns are largely the same as we did initially apart from `flex`. This dynamically sizes the field relative to the others so a `flex: 1.3` will be slightly larger than `flex: 1` and, together, fill all of the remaining space left over by our fixed width id column.
435 Refresh your browser and you should have a fully populated grid. If you hover over or click any of the headings you will see that you are able to dynamically sort by any of the fields.
437 {@img grid-full.png The completed grid in all of it's glory}
441 In this tutorial, we've learnt the basics of how to utilize Ext Direct while getting experience with how to create Ext grids as well as writing some pretty advanced PHP. Take some time to experiment with other configuration options by [looking at the documentation](#!/api) and getting a feel for what can be achieved and what customizations can be made.
443 For reference, [here are the working source files](guides/direct_grid_pt1/reference-files.zip).
445 In the next tutorial, we'll harness a bit more of Ext Direct's power to run server-side functions to create, update and delete from our MySQL database building on top of our current work.