A very quick and simple fxDao client example
// August 3rd, 2009 // No Comments » // fxDao
About one month ago I released fxDao v 1.0.0, a simple PHP gateway used to execute queries on the server specifying them directly in your ActionScript code.
The main difference between the fxDao approach and others like the one of AS3FlexDB is that the main application code is loosely coupled with it. Using fxDao your main application calls static methods from DAO classes. Encapsulating the data access logic into DAO classes brings the advantage that in case data access logic changes, you have to rewrite only the DAO classes, leaving the rest of the application as is.
In this article I’ll show a very simple ActionScript DAO class example.
The main application code is listed below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" pageTitle="fxDao DAO Example" layout="vertical" horizontalAlign="left" paddingTop="10" paddingRight="10" paddingBottom="10" paddingLeft="10" width="100%" backgroundColor="#ffffff" initialize="onInitialize(event);" applicationComplete="onComplete(event);" viewSourceURL="srcview/index.html"> <mx:Script> <![CDATA[ import model.Contact; import utils.FxDaoUtils; import dao.ContactsDao; import mx.collections.ArrayCollection; import mx.events.FlexEvent; [Bindable] private var _data:ArrayCollection; private function onInitialize(event:FlexEvent):void { FxDaoUtils.loadProperties(); } private function onComplete(event:FlexEvent):void { doReadAll(); } private function doReadAll():void { ContactsDao.readAll( function(list:ArrayCollection):void { _data = list; } ); } private function doSaveNew():void { var obj:Contact = getObj(); ContactsDao.create( obj, function(id:Number):void { obj.id = id; _data.addItem(obj); datagrid.selectedIndex = _data.length - 1; datagrid.scrollToIndex(datagrid.selectedIndex); } ); } private function doUpdate():void { var obj:Contact = getObj(); ContactsDao.update( obj, function():void { setObj(obj); } ); } private function doDelete():void { var obj:Contact = getObj(); ContactsDao.deleteById( obj.id, function():void { unsetObj(obj); } ); } /** * Return a Contact instance from form data. */ private function getObj():Contact { var obj:Contact = new Contact(); obj.id = Number(inId.text); obj.firstName = inFirstName.text; obj.lastName = inLastName.text; obj.email = inEmail.text; return obj; } /** * Update Contact object in data set. */ private function setObj(obj:Contact):void { for each (var item:Contact in _data) { if (item.id == obj.id) { item.firstName = obj.firstName; item.lastName = obj.lastName; item.email = obj.email; break; } } } /** * Remove object from data set. */ private function unsetObj(obj:Contact):void { var i:Number = 0; for each (var item:Contact in _data) { if (item.id == obj.id) { _data.removeItemAt(i); datagrid.selectedIndex = -1; break; } i ++; } } ]]> </mx:Script> <mx:HBox verticalAlign="middle"> <mx:Image source="@Embed('../assets/fxDaoTiny.png')" /> <mx:Label text="DAO Class Example" fontSize="18" color="#666666"> <mx:filters> <flash.filters:DropShadowFilter xmlns:flash.filters="flash.filters.*" angle="45" blurX="4" blurY="4" distance="2" alpha=".4" color="0x000000" /> </mx:filters> </mx:Label> </mx:HBox> <mx:Panel width="100%" height="100%" title="Datagrid" fontFamily="Arial" fontSize="12"> <mx:DataGrid id="datagrid" width="100%" height="100%" dataProvider="{_data}"> <mx:columns> <mx:DataGridColumn headerText="ID" dataField="id" /> <mx:DataGridColumn headerText="First name" dataField="firstName" /> <mx:DataGridColumn headerText="Last name" dataField="lastName" /> <mx:DataGridColumn headerText="E-mail" dataField="email" /> </mx:columns> </mx:DataGrid> </mx:Panel> <mx:Panel width="100%" title="Detail" fontFamily="Arial" fontSize="12"> <mx:Form id="form" width="50%"> <mx:FormItem label="ID"> <mx:TextInput id="inId" text="{datagrid.selectedItem.id}" enabled="false"/> </mx:FormItem> <mx:FormItem label="First name"> <mx:TextInput id="inFirstName" text="{datagrid.selectedItem.firstName}" /> </mx:FormItem> <mx:FormItem label="Last name"> <mx:TextInput id="inLastName" text="{datagrid.selectedItem.lastName}" /> </mx:FormItem> <mx:FormItem label="E-mail"> <mx:TextInput id="inEmail" text="{datagrid.selectedItem.email}" /> </mx:FormItem> </mx:Form> </mx:Panel> <mx:HBox width="100%"> <mx:Button label="Save as new" click="doSaveNew();" /> <mx:Button label="Update" click="doUpdate();" enabled="{datagrid.selectedItem != null}" /> <mx:Button label="Delete" click="doDelete();" enabled="{datagrid.selectedItem != null}" /> <mx:Spacer width="100%" /> <mx:Button label="Read all" click="doReadAll();" /> </mx:HBox> </mx:Application> |
The application loads a configuration file on startup at line 25. The configuration file contains the fxDao entry point URL and the hash key used to calculate a checksum string which is passed to the gateway on each request. The checksum is used to build up a very basic level of security. Security in fxDao is certainly something we have to focus better on in the next future.
Once the application initialization is completed, a first call to the DAO class populates the DataGrid at line35. The ContactsDao.readAll method expects a callback Function as parameter. That function will be invoked once the result will be available: after all we are playing with asynchronous service calls.
The callback function at line 36 takes an ArrayCollection as parameter which means that the DAO class will serialize and deserialize data without the need for the main application to know anything about the data structures exchanged underneath. This is the reason why the main application can be considered loosely coupled with fxDao. The Value Object used in this example is Contact and its very simple structure is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package model { [Bindable] public class Contact { // ------------------------------------------------------------------------- // // Properties // // ------------------------------------------------------------------------- public var id:Number = -1; public var firstName:String = ""; public var lastName:String = ""; public var email:String = ""; // ------------------------------------------------------------------------- // // Constructor // // ------------------------------------------------------------------------- /** * Constructor * * Assumes an XML structure in the form: * * <data> * <c1>123</c1> * <c2>first name</c2> * <c3>last name</c3> * <c4>email</c4> * </data> * */ public function Contact(data:XML = null) { if (data != null) { id = Number(data.c1); firstName = data.c2; lastName = data.c3; email = data.c4; } } } } |
All other create, delete and update methods work more or less the same way. As you can see, this example application is very simple and let you remotely read, insert, update and delete records.
The ContactsDao class encapsulates the SQL queries used to read and write records into static methods invoked by the main application. Queries are executed through the fxDao gateway which means that an HTTP service is used to send commands to the server. This is why method calls are asynchronous.
The ContactsDao class source code is listed below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | package dao { import model.Contact; import mx.collections.ArrayCollection; import mx.managers.CursorManager; import mx.rpc.AsyncToken; import mx.rpc.events.ResultEvent; import utils.FxDaoUtils; public class ContactsDao { // ------------------------------------------------------------------------- // // CRUD methods // // ------------------------------------------------------------------------- // ----------------------------------- // Create // ----------------------------------- public static function create(obj:Contact, userHandler:Function):void { var query:String = "INSERT INTO contacts SET " + "first_name='" + dquote(obj.firstName) + "', " + "last_name='" + dquote(obj.lastName) + "', " + "email='" + dquote(obj.email) + "'"; doExecute(query, onCreate, userHandler); } private static function onCreate(event:ResultEvent, userHandler:Function):void { var id:Number = Number(event.result.rs.@insert_id); userHandler(id); } // ----------------------------------- // Read // ----------------------------------- public static function readAll(userHandler:Function):void { var query:String = "SELECT * FROM contacts"; doExecute(query, onReadAll, userHandler); } private static function onReadAll(event:ResultEvent, userHandler:Function):void { var list:ArrayCollection = new ArrayCollection(); for each (var row:XML in event.result.rs.r) { list.addItem(new Contact(row)); } if (userHandler != null) { userHandler(list); } } // ----------------------------------- // Update // ----------------------------------- public static function update(obj:Contact, userHandler:Function):void { var query:String = "UPDATE contacts SET " + "first_name='" + dquote(obj.firstName) + "', " + "last_name='" + dquote(obj.lastName) + "', " + "email='" + dquote(obj.email) + "' " + "WHERE id=" + obj.id; doExecute(query, onUpdate, userHandler); } private static function onUpdate(event:ResultEvent, userHandler:Function):void { if (userHandler != null) { userHandler(); } } // ----------------------------------- // Delete // ----------------------------------- public static function deleteById(id:Number, userHandler:Function):void { var query:String = "DELETE FROM contacts WHERE id=" + id; doExecute(query, onDeleteById, userHandler); } private static function onDeleteById(event:ResultEvent, userHandler:Function):void { if (userHandler != null) { userHandler(); } } // ------------------------------------------------------------------------- // // Private methods // // ------------------------------------------------------------------------- /** * Execute given query. */ private static function doExecute(query:String, resultHandler:Function, userHandler:Function = null):void { CursorManager.setBusyCursor(); var params:Object = new Object(); params.query = query; params.checksum = FxDaoUtils.calculateChecksum(query); var token:AsyncToken = FxDaoUtils.service.send(params); token.myData = {resultHandler: resultHandler, userHandler:userHandler}; } /** * Double quotes in given string. */ private static function dquote(value:String):String { return value.replace("'", "''"); } } } |
You can download the full source code of the example on the fxDao Google Code project home.
If you like fxDao and want to contribute in any way feel free to submit your request! Any kind of help will be appreciated.




