I recently wrote this AS3 Class for interacting with drupal from Flex using the AMFPHP and Services module. Not sure if this has been done already or if this code will be useful but I am releasing it into the Public Domain. Hopefully it could be expanded on by someone with more time to make it a full featured class.
I have got it working with the following setup: Drupal 5.11, AMFPHP 1.9 Beta 2, Services Module 5.x-0.91, Views Module 5.x-1.6. I am using Flex Builder 3 and AS3.
There are some clear parts which are left out (like a nodeLoad function although there is a nodeSave). I can't put any more time into this however since I've achieved what I need for my application. Please feel free to use it in any way you like. Also example Flex code is included. Have fun.
The Package
package drupal
{
// drupalAMFPHP and associated example code were originally developed by Joshua Weinberg, Zonit Structured Solutions, 10/28/08
//
// This work is hereby released into the Public Domain.
// To view a copy of the public domain dedication, visit
// http://creativecommons.org/licenses/publicdomain/
// or send a letter to
// Creative Commons,
// 171 Second Street, Suite 300,
// San Francisco, California, 94105, USA.
//
// drupalAMFPHP AS3 Class version 0.1
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.messaging.Channel;
import mx.messaging.ChannelSet;
import mx.messaging.channels.AMFChannel;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;
public class drupalAMFPHP extends EventDispatcher
{
public static var CONNECT_RESULT:String = "connectResult";
public static var CONNECT_FAULT:String = "connectFault";
public static var LOGIN_RESULT:String = "loginResult";
public static var LOGIN_FAULT:String = "loginFault";
public static var GETVIEW_RESULT:String = "getviewResult";
public static var GETVIEW_FAULT:String = "getviewFault";
public static var SAVE_RESULT:String = "saveResult";
public static var SAVE_FAULT:String = "saveFault";
public static var USERNAME_BINDABLE_EVENT:String = "usernameUpdate";
public static var SYSTEM_SERVICE_FLAG:Number= 0x00000001;
public static var USER_SERVICE_FLAG:Number= 0x00000010;
public static var VIEWS_SERVICE_FLAG:Number= 0x00000100;
public static var NODE_SERVICE_FLAG:Number= 0x00001000;
private var _APIKey:String="";
private var _sessionID:String="";
private var _userID:String="";
private var _userName:String="";
private var drupalSystemService:RemoteObject;
private var drupalUserService:RemoteObject;
private var drupalViewsService:RemoteObject;
private var drupalNodeService:RemoteObject;
public function drupalAMFPHP(endpointURI:String, serviceFlags:Number):void {
var amfChannel:Channel;
var amfChannelSet:ChannelSet;
if ((serviceFlags & SYSTEM_SERVICE_FLAG) == SYSTEM_SERVICE_FLAG) {
// Setup drupalSystemService
drupalSystemService=new RemoteObject();
drupalSystemService.source="system";
drupalSystemService.destination="amfphp";
drupalSystemService.addEventListener(FaultEvent.FAULT,defaultFaultHandler);
amfChannel=new AMFChannel("my-amfphp",endpointURI);
amfChannelSet=new ChannelSet();
amfChannelSet.addChannel(amfChannel);
drupalSystemService.channelSet = amfChannelSet;
// connect method for this service
drupalSystemService.connect.addEventListener(FaultEvent.FAULT,drupalSystemServiceConnectFaultHandler);
drupalSystemService.connect.addEventListener(ResultEvent.RESULT,drupalSystemServiceConnectResultHandler);
}
if ((serviceFlags & USER_SERVICE_FLAG) == USER_SERVICE_FLAG) {
// Setup drupalLoginService
drupalUserService=new RemoteObject();
drupalUserService.source="user";
drupalUserService.destination="amfphp";
drupalUserService.addEventListener(FaultEvent.FAULT,defaultFaultHandler);
amfChannel=new AMFChannel("my-amfphp",endpointURI);
amfChannelSet=new ChannelSet();
amfChannelSet.addChannel(amfChannel);
drupalUserService.channelSet = amfChannelSet;
// connect method for this service
drupalUserService.login.addEventListener(FaultEvent.FAULT,drupalUserServiceLoginFaultHandler);
drupalUserService.login.addEventListener(ResultEvent.RESULT,drupalUserServiceLoginResultHandler);
}
if ((serviceFlags & VIEWS_SERVICE_FLAG) == VIEWS_SERVICE_FLAG) {
// Setup drupalViewsService
drupalViewsService=new RemoteObject();
drupalViewsService.source="views";
drupalViewsService.destination="amfphp";
drupalViewsService.addEventListener(FaultEvent.FAULT,defaultFaultHandler);
amfChannel=new AMFChannel("my-amfphp",endpointURI);
amfChannelSet=new ChannelSet();
amfChannelSet.addChannel(amfChannel);
drupalViewsService.channelSet = amfChannelSet;
// connect method for this service
drupalViewsService.getView.addEventListener(FaultEvent.FAULT,drupalViewsServiceGetViewFaultHandler);
drupalViewsService.getView.addEventListener(ResultEvent.RESULT,drupalViewsServiceGetViewResultHandler);
}
if ((serviceFlags & NODE_SERVICE_FLAG) == NODE_SERVICE_FLAG) {
// Setup drupalNodeService
drupalNodeService=new RemoteObject();
drupalNodeService.source="node";
drupalNodeService.destination="amfphp";
drupalNodeService.addEventListener(FaultEvent.FAULT,defaultFaultHandler);
amfChannel=new AMFChannel("my-amfphp",endpointURI);
amfChannelSet=new ChannelSet();
amfChannelSet.addChannel(amfChannel);
drupalNodeService.channelSet = amfChannelSet;
// connect method for this service
drupalNodeService.save.addEventListener(FaultEvent.FAULT,drupalNodeServiceSaveFaultHandler);
drupalNodeService.save.addEventListener(ResultEvent.RESULT,drupalNodeServiceSaveResultHandler);
}
}
public function connect():void {
if (drupalSystemService) {
drupalSystemService.connect(_APIKey);
}
}
public function login(u:String, p:String):void {
//trace("In class login");
if (drupalUserService) {
drupalUserService.login(_APIKey, _sessionID,u,p);
}
}
public function getView(viewName:String,... fields):void {
if (drupalViewsService) {
if (fields.length) {
drupalViewsService.getView(_APIKey,_sessionID,viewName,[ 'nid','vid','type','title','uid','status','changed'].concat(fields[0]));
} else {
drupalViewsService.getView(_APIKey,_sessionID,viewName,[ 'nid','vid','type','title','uid','status','changed']);
}
}
}
public function saveNode(nodeObject:Object):void {
if (drupalNodeService) {
nodeObject.uid=_userID;
nodeObject.name=_userName;
drupalNodeService.save(_APIKey,_sessionID,nodeObject);
}
}
/****** Event Handlers *****/
// Default Fault
public function defaultFaultHandler(e:FaultEvent):void {
dispatchEvent(e);
}
// System Connect Result
public function drupalSystemServiceConnectResultHandler(e:ResultEvent):void {
//trace("in connect result");
_sessionID=e.result.sessid;
// The user may be logged in already. If so, call the event handler for User login.
if (e.result.user.userid) {
drupalUserServiceLoginResultHandler(e);
}
//trace("session ID: "+_sessionID);
var mev:ResultEvent=new ResultEvent(CONNECT_RESULT,e.bubbles,e.cancelable,e.result,e.token,e.message);
dispatchEvent(mev);
}
// System Connect Fault
public function drupalSystemServiceConnectFaultHandler(e:FaultEvent):void {
var mev:FaultEvent=new FaultEvent(CONNECT_FAULT,e.bubbles,e.cancelable,e.fault,e.token,e.message);
dispatchEvent(mev);
}
// User Login Result
public function drupalUserServiceLoginResultHandler(e:ResultEvent):void {
//trace("in user result");
_sessionID=e.result.sessid;
_userID=e.result.user.userid;
_userName=e.result.user.name; dispatchEvent(new Event(USERNAME_BINDABLE_EVENT));
//trace("session ID: "+_sessionID);
var mev:ResultEvent=new ResultEvent(LOGIN_RESULT,e.bubbles,e.cancelable,e.result,e.token,e.message);
dispatchEvent(mev);
}
// User Login Fault
public function drupalUserServiceLoginFaultHandler(e:FaultEvent):void {
var mev:FaultEvent=new FaultEvent(LOGIN_FAULT,e.bubbles,e.cancelable,e.fault,e.token,e.message);
dispatchEvent(mev);
}
// Views GetView Result
public function drupalViewsServiceGetViewResultHandler(e:ResultEvent):void {
var mev:ResultEvent=new ResultEvent(GETVIEW_RESULT,e.bubbles,e.cancelable,e.result,e.token,e.message);
dispatchEvent(mev);
}
// Views GetView Fault
public function drupalViewsServiceGetViewFaultHandler(e:FaultEvent):void {
var mev:FaultEvent=new FaultEvent(GETVIEW_FAULT,e.bubbles,e.cancelable,e.fault,e.token,e.message);
dispatchEvent(mev);
}
// Node Save Result
public function drupalNodeServiceSaveResultHandler(e:ResultEvent):void {
var mev:ResultEvent=new ResultEvent(SAVE_RESULT,e.bubbles,e.cancelable,e.result,e.token,e.message);
dispatchEvent(mev);
}
// Node Save Fault
public function drupalNodeServiceSaveFaultHandler(e:FaultEvent):void {
var mev:FaultEvent=new FaultEvent(SAVE_FAULT,e.bubbles,e.cancelable,e.fault,e.token,e.message);
dispatchEvent(mev);
}
/****** Setters and Getters *****/
public function get sessionID():String {
return _sessionID;
}
public function get userID():String {
return _userID;
}
[Bindable(event="usernameUpdate")]
public function get userName():String {
//trace("In username getter");
return _userName;
}
public function set APIKey(k:String):void {
if (k) {
_APIKey=k;
}
}
}
}The Example MXML:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
// drupalAMFPHP and this example code were originally developed by Joshua Weinberg, Zonit Structured Solutions, 10/28/08
//
// This work is hereby released into the Public Domain.
// To view a copy of the public domain dedication, visit
// http://creativecommons.org/licenses/publicdomain/
// or send a letter to
// Creative Commons,
// 171 Second Street, Suite 300,
// San Francisco, California, 94105, USA.
//
import flash.events.Event;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import drupal.drupalAMFPHP;
// The object which holds the remoteobjects
[Bindable] public var drupalRemote:drupalAMFPHP=null;
// Set the new user page here
private const drupalNewUserPage:String="https://URL/user/register";
// Set the password recovery page here
private const drupalPasswordPage:String="https://URL/user/password";
private var viewResult:Array;
public function drupalConnect():void {
if (drupalRemote) { return; }
// Set the drupal URL here
drupalRemote=new drupalAMFPHP("http://URL/services/amfphp",drupalAMFPHP.SYSTEM_SERVICE_FLAG|drupalAMFPHP.USER_SERVICE_FLAG|drupalAMFPHP.VIEWS_SERVICE_FLAG|drupalAMFPHP.NODE_SERVICE_FLAG);
// Set the API KEY here
drupalRemote.APIKey="ebbc5d5591b83536d64e8dbf23efec1c";
drupalRemote.addEventListener(drupalAMFPHP.CONNECT_RESULT,drupalSystemServiceConnectResultHandler);
drupalRemote.addEventListener(drupalAMFPHP.CONNECT_FAULT,drupalSystemServiceConnectFaultHandler);
drupalRemote.addEventListener(drupalAMFPHP.LOGIN_RESULT,drupalUserServiceLoginResultHandler);
drupalRemote.addEventListener(drupalAMFPHP.LOGIN_FAULT,drupalUserServiceLoginFaultHandler);
drupalRemote.addEventListener(drupalAMFPHP.GETVIEW_RESULT,drupalViewsServiceGetViewResultHandler);
drupalRemote.addEventListener(drupalAMFPHP.GETVIEW_FAULT,drupalViewsServiceGetViewFaultHandler);
drupalRemote.addEventListener(drupalAMFPHP.SAVE_RESULT,drupalNodeServiceSaveResultHandler);
drupalRemote.addEventListener(drupalAMFPHP.SAVE_FAULT,drupalNodeServiceSaveFaultHandler);
drupalRemote.connect();
}
/************** Drupal Functions **************/
public function userLoggedIn():void {
infoMessageTextArea.text="Logged in as "+drupalRemote.userName;
}
public function getView():void {
viewResultMsg.text="";
drupalRemote.getView(viewName.text,['body']);
}
public function saveNode(n:Object):void {
n.title=title.text;
n.body=body.text;
drupalRemote.saveNode(n);
}
/*************** Drupal Helper Functions **************************/
public function openDrupalNewUserPage():void {
var ur:URLRequest=new URLRequest(drupalNewUserPage);
navigateToURL(ur,"_blank");
}
public function openDrupalPasswordPage():void {
var ur:URLRequest=new URLRequest(drupalPasswordPage);
navigateToURL(ur,"_blank");
}
/*************** Drupal remoteObject ResultHandlers ***************/
public function drupalSystemServiceConnectResultHandler(event:ResultEvent):void {
if (Number(drupalRemote.userID)==0) {
infoMessageTextArea.text="Please log in to Load/Save nodes:";
} else {
userLoggedIn();
}
}
public function drupalViewsServiceGetViewResultHandler(event:ResultEvent):void {
if (event.result) {
viewResultDataGrid.dataProvider=event.result;
} else {
viewResultMsg.text="GetView did not return a node";
}
}
public function drupalNodeServiceSaveResultHandler(event:ResultEvent):void {
nodeMsg.text="Done";
// Call getView to show it has been updated on the server
getView();
}
public function drupalUserServiceLoginResultHandler(event:ResultEvent):void {
if (Number(drupalRemote.userID)!=0) {
userLoggedIn();
}
}
/*************** Drupal remoteObject FaultHandlers ***************/
public function drupalSystemServiceConnectFaultHandler(event:FaultEvent):void {
infoMessageTextArea.text=event.fault.faultString;
}
public function drupalNodeServiceSaveFaultHandler(event:FaultEvent):void {
nodeMsg.text=event.fault.faultString;
}
public function drupalViewsServiceGetViewFaultHandler(event:FaultEvent):void {
viewResultMsg.text=event.fault.faultString;
}
public function drupalUserServiceLoginFaultHandler(event:FaultEvent):void {
nodeMsg.text=event.fault.faultString;
}
]]>
</mx:Script>
<mx:Canvas id="fileCanvas" width="295" height="236" visible="true" borderStyle="solid" borderColor="0x000000" backgroundAlpha=".8" backgroundColor="0x000010" cornerRadius="15" left="7" y="5">
<mx:Button label="Close" click="fileCanvas.visible=false;" horizontalCenter="108" bottom="10"/>
<mx:Label y="10" id="fileTitle" text="Drupal User Service" color="#FFFFFF" textAlign="center" horizontalCenter="0" fontWeight="bold"/>
<mx:Canvas id="loginFileCanvas" visible="true" horizontalCenter="-1" width="100%" height="225" y="9">
<mx:Label x="32" y="80" text="Username" color="#FFFFFF"/>
<mx:Label x="32" y="110" text="Password" color="#FFFFFF"/>
<mx:TextInput id="drupalUsernameTextInput" x="102" y="78" backgroundColor="#F4F4F4" cornerRadius="10"/>
<mx:TextInput id="drupalPasswordTextInput" displayAsPassword="true" x="102" y="108" backgroundColor="#F4F4F4" cornerRadius="10"/>
<mx:LinkButton x="7" y="167" height="18" width="132" color="#FFFFFF" useHandCursor="true" buttonMode="true" click="openDrupalNewUserPage()" label="Need a Username?" textAlign="center"/>
<mx:LinkButton x="133" y="168" height="18" width="155" color="#FFFFFF" useHandCursor="true" buttonMode="true" click="openDrupalPasswordPage()" label="Forgot your Password?" textAlign="center"/>
<mx:Button x="206" y="138" label="Login" click="drupalRemote.login(drupalUsernameTextInput.text,drupalPasswordTextInput.text);"/>
<mx:Button x="32" y="138" label="Connect" click="drupalConnect();"/>
<mx:Text id="nodeMsg" y="50" width="273" color="#FFFFFF" textAlign="center" x="10"/>
</mx:Canvas>
<mx:Text id="infoMessageTextArea" y="27" width="273" horizontalCenter="0" color="#FFFFFF" textAlign="center"/>
</mx:Canvas>
<mx:Label x="310" y="31" text="Views Service"/>
<mx:Label x="310" y="57" text="View Name:"/>
<mx:TextInput x="388" y="55" width="250" id="viewName"/>
<mx:Button x="646" y="55" label="Get View" click="getView();"/>
<mx:Text x="520" y="31" id="viewResultMsg" fontWeight="bold"/>
<mx:DataGrid x="309" y="99" width="481" id="viewResultDataGrid">
<mx:columns>
<mx:DataGridColumn headerText="NID" width="45" dataField="nid"/>
<mx:DataGridColumn headerText="Title" dataField="title"/>
<mx:DataGridColumn headerText="Body" dataField="body"/>
</mx:columns>
</mx:DataGrid>
<mx:Label x="309" y="269" text="Node Service"/>
<mx:Text x="520" y="269" id="nodeResultMsg"/>
<mx:TextInput x="388" y="317" text="{viewResultDataGrid.selectedItem.title}"/>
<mx:TextInput x="388" y="345" text="{viewResultDataGrid.selectedItem.type}" editable="false"/>
<mx:TextInput x="388" y="373" text="{viewResultDataGrid.selectedItem.userid}" editable="false"/>
<mx:TextInput x="388" y="401" text="{viewResultDataGrid.selectedItem.status}" editable="false"/>
<mx:TextInput x="388" y="429" text="{viewResultDataGrid.selectedItem.changed}" editable="false"/>
<mx:Label x="309" y="459" text="Body:" id="body"/>
<mx:Label x="309" y="431" text="Changed:"/>
<mx:Label x="309" y="403" text="Status:"/>
<mx:Label x="309" y="375" text="User ID:"/>
<mx:Label x="309" y="347" text="Type:"/>
<mx:Label x="309" y="319" text="Title:" id="title"/>
<mx:Label x="309" y="293" text="NID:"/>
<mx:Label x="519" y="293" text="VID:"/>
<mx:Text x="388" y="293" text="{viewResultDataGrid.selectedItem.nid}" fontWeight="bold" color="#000000"/>
<mx:Text x="557" y="293" text="{viewResultDataGrid.selectedItem.vid}" fontWeight="bold" color="#000000"/>
<mx:TextArea x="389" y="458" width="317" height="102" text="{viewResultDataGrid.selectedItem.body}"/>
<mx:Button x="389" y="568" label="Save Node" click="saveNode(viewResultDataGrid.selectedItem);"/>
</mx:Application>
Comments
thanks for this! MIght be
thanks for this! MIght be exactly what I need at this point. Gonna take me some time to try out and reverse engineer...I am an AS3 newb, but I really want to learn how to make Flex/Air and Drupal talk to each other. Thanks for you help! Someone more skilled from me probably have a better response than me, but I really appreciate your work.