It’s been a while since I last wrote, sorry! I’ve been busy with work, thesis and some other suffs (which I’ll be posting about in the next days).
One of those is AMFPhp: a method to connect Flash with Php.
Why AMF instead of JSON or XML? Basically because AMF is more mature than JSON, offer a ready-made and really complete set of classes, many utilities like the connection debugger component, a great Php implementation, and, above all, CakeAMFPhp. (AMF is also a binary protocol on top of HTTP, so performance should be better than XML)
CakeAMFPhp is the integration of AMFPhp and Cake, a Rails-inspired php framework. With Cake I’ve quickly build a prototype with the Bake command-line utility. Then I’ve started implementing the methods for the AMF calls. Thanks to the great database abstraction, every method is only few lines long.
Since CakeAMFPhp is a beta, I’ve found some problems, for which I’ve found a quick fix that I’ll explain shortly.
To start a CakeAMFPhp project, simply download the required libraries as explained in this tutorial. (If you are new to Cake you should also see this)
Then in your controller, for example GalleriesController, put this:
vendor("cakeamfphp/amf-core/util/MethodTable"); vendor('cakeamfphp/amf-core/adapters/lib/Arrayft'); vendor('cakeamfphp/amf-core/adapters/lib/Arrayf'); class GalleriesController extends AppController { ... function GalleriesController() { //AMF: $this->methodTable = MethodTable::create(__FILE__); parent::__construct(); }
In the line 11 we call the automatic method table constructor of AMFPhp: it read the javadoc-like comments in the file and do all the magic:
/** * @desc Return the list of public galleries * @access remote * @pagesize 25 */ function getGalleries($offset = 0, $limit = 25) { $data = $this->Gallery->findAll(null, null, 'created DESC', $limit, $offset, 0); return $this->_arrayft($data, 'Gallery'); } function getGalleries_count() { return $this->Gallery->findCount(); }
The @access remote
tag specify that the getGalleries method is callable from flash:
var pc:PendingCall = ser.getGalleries();
pc.responder = new RelayResponder(this, “handleResult”, “handleError”);
[/as]
The getGalleries_count()
method is needed for the pageable recordset:
var rs = RecordSet(re.result);
rs.addEventListener(‘modelChanged’, this); //Listen for updateItems
this.totalItems = rs.getLength();
for(var i:Number=startFrom; i < l; i++) {
item = rs.getItemAt(i);
if(i < rs.getNumberAvailable()) { //It is already fetched
... //Process a row
}
}
[/as]
getGalleries
return only the first 25 row from the database. When the data is loaded in flash, rs.getLength()
method return the value from getGalleries_count()
. getItemAt
return an item or a future, we check if the item is loaded in the line 8. If the item isn’t from the ones loaded, it is automatically requested from the server when we call getItemAt
. When it arrives, the modelChanged
method is called:
var rs = this.rs;
var item:Object;
if(info.eventName == “updateItems”) {
for(var i:Number=info.firstItem; i <= info.lastItem; i++) { item = rs.getItemAt(i); target.addItem(item); } } } [/as] in the info object there are the rows received, you can configure Flash to get only the item required or the page containing it. That's all, simply add the
@access remote
tag, a *methodname*_count
method and it works.You can find more information on pageable recordsets here.
The _arrayft
is required for the issue I’ve talk about before: CakeAMFPhp 0.6 does not support sending recorset to flash, so this method is required to transform the data returned by the Cake database abstraction layer into a AMF-compatible recordset:
function _arrayft($data, $table) { $r = array(); if(!empty($data[$table])) { //Multi table query: if(is_array($data[$table][0])) { //Nested table: foreach($data[$table] as $t) { $r[] = $t; } } else { //Sigle record: foreach($data[$table] as $t) { $r[] = $t; } } } else { foreach($data as $t) { array_push($r, $t[$table]); } } return new Arrayf($r, array_keys($r[0]) ); }
For performance reason, it is suggested to use a 0 ‘recursive’ value in the find(..) call.
Okay, now I’m not sure how well this will perform but it appears to work so far. The following is a modified version of the amfBB example.
Which will return the following:
– Brian
Thanks, It is really useful with Has_one relationships, I have to try it with Has_Many to see what happens. Btw, I’m waiting for a new version of CakeAmfPhp with AMFPhp 2.0