{"id":787,"date":"2010-08-26T13:10:46","date_gmt":"2010-08-26T18:10:46","guid":{"rendered":"http:\/\/www.lonhosford.com\/lonblog\/?p=787"},"modified":"2015-07-31T18:25:51","modified_gmt":"2015-07-31T23:25:51","slug":"zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql","status":"publish","type":"post","link":"https:\/\/www.lonhosford.com\/lonblog\/2010\/08\/26\/zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql\/","title":{"rendered":"ZEND AMF (Action Message Format) Minimalist Example Using RemoteObject and MySQL"},"content":{"rendered":"<p>I always liked and appreciated the <a href=\"http:\/\/www.amfphp.org\/\" target=\"_blank\">AMFPHP implementation<\/a> of Adobe Action Message Format. I have seen it implemented in some robust applications and it held its own. <img loading=\"lazy\" decoding=\"async\" class=\"alignleft\" style=\"margin-right: 5px; border: 1px solid black;\" src=\"http:\/\/lh5.ggpht.com\/_e5pwU0LJbN8\/THaPGSfNSzI\/AAAAAAAAFsA\/cPvKMfUdzR4\/s800\/Zend_AMF_Minimalist_8-26-2010%2011-56-17%20AM.png\" alt=\"\" width=\"232\" height=\"171\" \/> Among its best features is the browser which is very handy for testing. However Adobe has now gotten involved with <a href=\"http:\/\/framework.zend.com\/download\/amf\" target = \"_blank\">Zend AMF<\/a> and this is a quick shot at putting it together using the RemoteObject class.<\/p>\n<p>The first example I looked at is from Lee Brimelow&#8217;s <a href=\"http:\/\/gotoandlearn.com\/play.php?id=90\" target=\"_blank\">Introduction to ZendAMF<\/a> at gotoAndLearn.com. This is a great example and worth the watch to get a rounded view of using Zend AMF. He uses NetConnection and Responder classes in Flash CS4.  You can use his example in Flex and Air.<\/p>\n<figure style=\"width: 111px\" class=\"wp-caption alignright\"><a href=\"http:\/\/www.amazon.com\/gp\/product\/B003KG2HLG?ie=UTF8&amp;tag=hosfordusa&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B003KG2HLG5\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"  \" title=\"Adobe Flash Builder 4 and Flex 4 - Essential Training\" src=\"http:\/\/lh5.ggpht.com\/_e5pwU0LJbN8\/THaJ7e_VZDI\/AAAAAAAAFr4\/6gLBuTgzkq0\/s800\/FlashBuilder4AndFlex441KcCjdUF%2BL._SL160_.jpg\" alt=\"Adobe Flash Builder 4 and Flex 4 - Essential Training\" \" width=\"111\"  height=\"160\" \/><\/a><figcaption class=\"wp-caption-text\">Learn More About Flex&nbsp;4<\/figcaption><\/figure>\n<p>Eventually I put Zend AMF to practical use by revamping <a href=\"http:\/\/www.defineit.com\" target = \"_blank\">DefineIt.com<\/a> to use it along with the <a href=\"https:\/\/www.lonhosford.com\/lonblog\/2010\/09\/27\/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example\/\">Parsley framework<\/a>.<\/p>\n<p>Flash CS4 does not have a native RemoteObject class, so that leads us to using Flex.<\/p>\n<p><strong>Download files<\/strong><br \/>\nYou can build this with the free Flex SDK by using the code in the src folder. This example was built with Flex 4.<\/p>\n<ul style=\"padding-top: 5px;\">\n<li><a href=\"https:\/\/www.lonhosford.com\/content\/flex\/amf\/zend\/ZendAMFRemoteObjectGetTable_Air.fxp\">Flex Builder 4 Air Project<\/a><\/li>\n<li><a href=\"https:\/\/www.lonhosford.com\/content\/flex\/amf\/zend\/ZendAMFRemoteObjectGetTable_Flex.fxp\">Flex Builder 4 Flex Project<\/a><\/li>\n<li><a href=\"http:\/\/framework.zend.com\/download\/amf\" target = \"_blank\">Zend AMF<\/a> &#8211; Download and decompress into a folder on your web server. You need to adjust line 26 of the Zend AMF gateway script shown below to account for the path the Zend folder&#8217;s parent folder.<\/li>\n<\/ul>\n<p>The following uses the code from the Flex example, but other than the Application and WindowedApplication tags the code is the same.<\/p>\n<p><strong>Application Class &#8211; ZendAMFRemoteObjectGetTable_Flex<\/strong><br \/>\nRather than use a services-config.xml file linked to the compiler line, I choose to include the channel information in the MXML. More on this method is detailed by Chris Callendar&#8217;s post <a href=\"http:\/\/flexdevtips.blogspot.com\/2009\/05\/using-flex-and-amfphp-without-services.html\" target = \"_blank\">Using Flex and AMFPHP without a services-config.xml file<\/a>.<\/p>\n<pre class=\"brush: as3; highlight: [32]; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--\r\nDemonstrates use of the RemoteObject to communicate with Zend AMF.\r\n&lt;p&gt;Author: Lon Hosford https:\/\/www.lonhosford.com 908 996 3773&lt;\/p&gt;\r\n--&gt;\r\n&lt;s:Application xmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot;\r\n\t\t\t   xmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot;\r\n\t\t\t   xmlns:mx=&quot;library:\/\/ns.adobe.com\/flex\/mx&quot; minWidth=&quot;955&quot; minHeight=&quot;600&quot;&gt;\r\n\t&lt;fx:Declarations&gt;\r\n\t\t&lt;!-- Alternative to services-config.xml added to the compiler option services --&gt;\r\n\t\t&lt;s:ChannelSet id = &quot;zend_amf_channel_set&quot;&gt;\r\n\t\t\t&lt;s:channels&gt;\r\n\t\t\t\t&lt;s:AMFChannel uri=&quot;{GATEWAY_URL}&quot;\/&gt;\r\n\t\t\t&lt;\/s:channels&gt;\r\n\t\t&lt;\/s:ChannelSet&gt;\r\n\t\t&lt;!-- MembershipService RemoteObject --&gt;\r\n\t\t&lt;s:RemoteObject\tid=&quot;members_ro&quot;\r\n\t\t\t\t\t\tdestination=&quot;zend-amf&quot;\r\n\t\t\t\t\t\tsource=&quot;MembershipService&quot;\r\n\t\t\t\t\t\tchannelSet=&quot;{zend_amf_channel_set}&quot;\r\n\t\t\t\t\t\tshowBusyCursor=&quot;true&quot;\r\n\t\t\t\t\t\tfault=&quot;membersError(event)&quot;&gt;\r\n\t\t\t&lt;s:method name=&quot;getAllMembers&quot; result=&quot;getAllMembersResult(event)&quot;\/&gt;\r\n\t\t&lt;\/s:RemoteObject&gt;\r\n\t&lt;\/fx:Declarations&gt;\r\n<\/pre>\n<p>[ad name=&#8221;Google Adsense&#8221;]<br \/>\nOn line 33 you need to set the GATEWAY_URL to match your configuration. You might want to use a default file name such as index.php for the gateway script so you only need a path to the folder.<\/p>\n<pre class=\"brush: as3; first-line: 26; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\t&lt;fx:Script&gt;\r\n\t\t&lt;!&amp;#91;CDATA&amp;#91;\r\n\t\t\timport mx.controls.Alert;\r\n\t\t\timport mx.events.FlexEvent;\r\n\t\t\timport mx.rpc.events.FaultEvent;\r\n\t\t\timport mx.rpc.events.ResultEvent;\r\n\t\t\t\/\/ &amp;#91;ADD YOUR HTTP URL TO THE GATEWAY PHP SCRIPT&amp;#93;\r\n\t\t\tprivate const GATEWAY_URL:String = &quot;http:\/\/YOUR_DOMAIN\/PATH_TO_GATEWAY SCRIPT\/&quot;;\r\n\t\t\t\/**\r\n\t\t\t * Member value object. Not used in this example. Included for information only.\r\n\t\t\t * Use this to convert the data received. In this example the DataGrid dataprovider\r\n\t\t\t * property converted the incoming amf array to an ArrayCollection and we mapped\r\n\t\t\t * using the DataGridColumn dataField property.\r\n\t\t\t * *\/\r\n\t\t\tprivate var memberData:MemberData;\r\n\t\t\t&amp;#91;Bindable&amp;#93;\r\n\t\t\tprivate var lang_title:String = &quot;Minimalist Zend AMF Example Using RemoteObject&quot;;\r\n\t\t\t\/**\r\n\t\t\t * Invoke RemoteObject members_ro getAllMembers method.\r\n\t\t\t * *\/\r\n\t\t\tprotected function getAllMembers():void\r\n\t\t\t{\r\n\t\t\t\tmembers_ro.getAllMembers();\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Empties the member_dg DataGrid.\r\n\t\t\t * *\/\r\n\t\t\tprotected function clearDataGrid():void\r\n\t\t\t{\r\n\t\t\t\tmember_dg.dataProvider = {};\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * RemoteObject members_ro ResultEvent handler for the remote getAllMembers method.\r\n\t\t\t * &lt;p&gt;Data arrives as an array and dataProvider property converts to ArrayCollection.\r\n\t\t\t * The member_dg DataGrid contains DataGridColumn to match the expected field using\r\n\t\t\t * the dataField property.&lt;\/p&gt;\r\n\t\t\t * *\/\r\n\t\t\tprotected function getAllMembersResult(e:ResultEvent):void\r\n\t\t\t{\r\n\t\t\t\tmember_dg.dataProvider = e.result; \/\/ ResultEvent result property is an array\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * RemoteObject members_ro default FaultEvent handler.\r\n\t\t\t * *\/\r\n\t\t\tprotected function membersError(e:FaultEvent):void\r\n\t\t\t{\r\n\t\t\t\tAlert.show(e.toString());\r\n\t\t\t}\r\n\t\t&amp;#93;&amp;#93;&gt;\r\n\t&lt;\/fx:Script&gt;\r\n<\/pre>\n<p>[ad name=&#8221;Google Adsense&#8221;]<br \/>\nThis is the UI. The member_dg DataGrid contains DataGridColumn to match the expected fields in the MemberData object using the dataField property. This is a one to one relationship, however you may find times where you need to construct your own fields such as a concatenation of first and last name and thus populate the DataGrid with your own collection object.<\/p>\n<pre class=\"brush: as3; first-line: 76; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\t&lt;s:VGroup horizontalAlign=&quot;center&quot; width=&quot;100%&quot; paddingTop=&quot;25&quot;&gt;\r\n\t\t&lt;s:Label text=&quot;{lang_title}&quot; fontSize=&quot;20&quot;\/&gt;\r\n\r\n\t\t&lt;mx:DataGrid  id=&quot;member_dg&quot;  height=&quot;100&quot;&gt;\r\n\t\t\t&lt;mx:columns&gt;\r\n\t\t\t\t&lt;mx:DataGridColumn headerText=&quot;Member Key&quot; dataField=&quot;memberKey&quot; width = &quot;100&quot;\/&gt;\r\n\t\t\t\t&lt;mx:DataGridColumn headerText=&quot;First Name&quot; dataField=&quot;firstName&quot;\/&gt;\r\n\t\t\t\t&lt;mx:DataGridColumn headerText=&quot;Last Name&quot; dataField=&quot;lastName&quot;\/&gt;\r\n\t\t\t\t&lt;mx:DataGridColumn headerText=&quot;Email Address&quot; dataField=&quot;emailAddress&quot; width=&quot;200&quot;\/&gt;\r\n\t\t\t&lt;\/mx:columns&gt;\r\n\t\t&lt;\/mx:DataGrid&gt;\r\n\t\t&lt;s:HGroup&gt;\r\n\t\t\t&lt;s:Button label=&quot;Get Members&quot; click=&quot;{getAllMembers();}&quot;\/&gt;\r\n\t\t\t&lt;s:Button label=&quot;Clear&quot; click=&quot;{clearDataGrid();}&quot;\/&gt;\r\n\t\t&lt;\/s:HGroup&gt;\r\n\t&lt;\/s:VGroup&gt;\r\n\r\n&lt;\/s:Application&gt;\r\n<\/pre>\n<p><strong>MemberData Value Object Class for Actionscript<\/strong><br \/>\nThis is the value object on the client side to define the field names for a member object. This is mapped to the server side on line 37 of the Zend AMF gateway script.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage\r\n{\r\n\t\/**\r\n\t * Value object defining the member data\r\n\t * *\/\r\n\t&#x5B;RemoteClass(alias=\"MemberData\")]\r\n\t&#x5B;Bindable]\r\n\tpublic class MemberData\r\n\t{\r\n\t\tpublic var memberKey:uint;\r\n\t\tpublic var firstName:String;\r\n\t\tpublic var lastName:String;\r\n\t\tpublic var emailAddress:String;\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>Zend AMF Gateway PHP Script<\/strong><br \/>\nThis is the gateway program for the Zend Amf. This is the file that is referenced on line 13 of the MXML file. In this example it was named index.php.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/**\r\n*  Sample Zend AMF gateway\r\n*  @return Endpoint &amp;#91;Zend Amf Endpoint&amp;#93;\r\n* *\/\r\n\r\n\/\/ Configurable values\r\n\/\/ Debugging values\r\n$debug = true;                             \/\/ Debugging status\r\nif ($debug)\r\n{\r\n\t\/\/ Report all errors, warnings, interoperability and compatibility\r\n\terror_reporting(E_ALL|E_STRICT);\r\n\t\/\/ Show errors with output\r\n\tini_set(&quot;display_errors&quot;, &quot;on&quot;);\r\n}\r\nelse\r\n{\r\n\terror_reporting(0);\r\n\tini_set(&quot;display_errors&quot;, &quot;off&quot;);\r\n}\r\n\/\/ Add the Zend AMF installation folder to the include path.\r\n\/\/ In this example the frameworks folder is a sibling folder to\r\n\/\/ this application folder. The frameworks folder contains the Zend\r\n\/\/ folder that is extracted from http:\/\/framework.zend.com\/download\/amf\r\nini_set(&quot;include_path&quot;, ini_get(&quot;include_path&quot;) . PATH_SEPARATOR . &quot;..\\\\frameworks&quot; );\r\n\r\n\/\/ Instantiate the Zend Amf server\r\nrequire_once &#039;Zend\/Amf\/Server.php&#039;;\r\n$server = new Zend_Amf_Server();\r\n\r\n\/\/ Register your service classes\r\nrequire_once &#039;MembershipService.php&#039;;\r\n$server-&gt;setClass(&quot;MembershipService&quot;);\r\n\r\n\/\/Map ActionScript value objects to the PHP value objects.\r\n$server-&gt;setClassMap(&quot;MemberData&quot;, &quot;MemberData&quot;);\r\n\r\n\/\/ Return the handle.\r\necho ($server-&gt;handle());\r\n\r\n?&gt;\r\n<\/pre>\n<p>[ad name=&#8221;Google Adsense&#8221;]<br \/>\n<strong>MembershipService Class<\/strong><br \/>\nThis is the service class that contains remote methods. Generally a the database and business logic is delegated to another API you write. In this case they are all together for simplicity.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/**\r\n*\tService class exposing the methods to deal with membership.\r\n*   This example includes business logic for simplicity of study.\r\n*\/\r\nrequire_once &#039;MemberData.php&#039;;\r\nclass MembershipService\r\n{\r\n\tpublic function MembershipService()\r\n\t{\r\n\t\t\/\/ Connect to MySql database.\r\n\t\t\/\/ Supply your own MySQL access values.\r\n\t\t\/\/ These are defaults when running on your own private computer.\r\n\t\tmysql_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;&quot;);\r\n\t\t\/\/ Select the database.\r\n\t\t\/\/ Supply your own database name.\r\n\t\tmysql_select_db(&quot;test&quot;);\r\n\t}\r\n\t\/**\r\n\t*\tGet all members and all fields.\r\n\t*\/\r\n\tpublic function getAllMembers()\r\n\t{\r\n\t\t\/\/ Array of MemberData objects.\r\n\t\t$members = array();\r\n\t\t\/\/ Selecting all fields and all records from table.\r\n\t\t\/\/ Supply your own table name and optionally your own SQL statement.\r\n\t\t$result = mysql_query(&quot;SELECT * FROM zend_amf_members&quot;);\r\n\t\t\/\/ Assuming mysql_query success. Slog through records.\r\n\t\twhile ($row = mysql_fetch_assoc($result))\r\n\t\t{\r\n\t\t\t\/\/ Create a MemberData value object and populate.\r\n\t\t\t$member = new MemberData();\r\n\t\t\t$member-&gt;memberKey = $row&#x5B;&quot;memberKey&quot;];\r\n\t\t\t$member-&gt;firstName = $row&#x5B;&quot;firstName&quot;];\r\n\t\t\t$member-&gt;lastName = $row&#x5B;&quot;lastName&quot;];\r\n\t\t\t$member-&gt;emailAddress = $row&#x5B;&quot;emailAddress&quot;];\r\n\t\t\tarray_push($members, $member);\r\n\t\t}\r\n\t\t\/\/ Return the members array to client.\r\n\t\treturn $members;\r\n\t}\r\n}\r\n?&gt;\r\n<\/pre>\n<p><strong>MemberData Value Object Class for PHP<\/strong><br \/>\nThis is the value object on the server side to define the field names for a member object. This is mapped to the client side on line 37 of the Zend AMF gateway script.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/**\r\n * Value object defining the member data\r\n * *\/\r\nclass MemberData\r\n{\r\n  public $memberKey;\t\/\/ uint\r\n  public $firstName;\t\/\/ String\r\n  public $lastName;\t\t\/\/ String\r\n  public $emailAddress;\t\/\/ String\r\n}\r\n?&gt;\r\n<\/pre>\n<p><strong>SQL To Create Testing Table<\/strong><br \/>\nThe PHP script uses zend_amf_members for the table and this is the SQL to create that table. In this example the database was called test.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSET SQL_MODE=\"NO_AUTO_VALUE_ON_ZERO\";\r\n\r\n--\r\n-- Database: `test`\r\n--\r\n\r\n-- --------------------------------------------------------\r\n\r\n--\r\n-- Table structure for table `zend_amf_members`\r\n--\r\n\r\nCREATE TABLE IF NOT EXISTS `zend_amf_members` (\r\n  `memberKey` int(10) unsigned NOT NULL auto_increment,\r\n  `firstName` varchar(30) NOT NULL default '',\r\n  `lastName` varchar(30) NOT NULL default '',\r\n  `emailAddress` varchar(50) NOT NULL default '',\r\n  PRIMARY KEY  (`memberKey`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Zend Amf Examples' AUTO_INCREMENT=7 ;\r\n\r\n--\r\n-- Dumping data for table `zend_amf_members`\r\n--\r\n\r\nINSERT INTO `zend_amf_members` (`memberKey`, `firstName`, `lastName`, `emailAddress`) VALUES\r\n(1, 'Donald', 'Duck', 'quacker@pond.com'),\r\n(2, 'Daffy', 'Duck', 'daft_2x@farm.org'),\r\n(3, 'Elmer', 'Fudd', 'elmer.fudd@hunters.net'),\r\n(4, 'Bugs', 'Bunny', 'whats_up_doc@underground.org'),\r\n(5, 'Yosemite', 'Sam', 'varmint_chaser@forest.com'),\r\n(6, 'Wile', 'Coyote', 'ceo@acme.com');\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I always liked and appreciated the AMFPHP implementation of Adobe Action Message Format. I have seen it implemented in some robust applications and it held its own. Among its best features is the browser which is very handy for testing. However Adobe has now gotten involved with Zend AMF and this is a quick shot [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[19,12,51,9,50],"class_list":["post-787","post","type-post","status-publish","format-standard","hentry","category-general","tag-actionscript","tag-air-adobe-integrated-runtime","tag-amf","tag-flex","tag-remoteobject"],"_links":{"self":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/787","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/comments?post=787"}],"version-history":[{"count":40,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/787\/revisions"}],"predecessor-version":[{"id":3701,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/787\/revisions\/3701"}],"wp:attachment":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/media?parent=787"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/categories?post=787"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/tags?post=787"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}