ActionScript 3 framework for interfacing with Drupal

Events happening in the community are now at Drupal community events on www.drupal.org.
arithmetric's picture

Thomas Saunders and I are releasing our ActionScript 3 (Flash 9/CS 3/Flex 2) framework for interfacing with Drupal sites running the Services and AMFPHP modules.

Our framework handles some of the basic aspects of connecting a Flash application with a Drupal site, invoking service methods, and retrieving data.

To download the ActionScript class files or view the API documentation, please see our site at:
http://thirdavedesign.com/drupalsite

Please let us know if you find this useful, and if you have any questions or suggestions.

Comments

Great !

opti-gdo's picture

I just downloaded the package.
Looks like there are some interesting and compact features in the framework.

I'm going to give it a try and I'll get back to you.

Thanks for sharing !

Cool stuff

spaceboii's picture

Thanks for doing this! I'll sure will be trying it out right away!
__
Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent disinclination to do so. - Douglas Adams

__
Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent disinclination to do so. - Douglas Adams

Nice Job

leavitron's picture

Thanks for the sharing. I will be pulling this into FlashDevelop asap., besides, no waves today.

great, an chance of some examples from anyone

amcc's picture

I'm just starting to get to grips with flash and drupal. It would be great to have some examples to see how everything works in flash.

this is nice

dubian's picture

with this nice little api and the older how to's this should make starting out a lot easier. If anyone has any examples i agree it would be nice though it should be easy enough to figure out how to adapt the older how to docs so they still work...

Thanks again!

this is what i'm using so far

amcc's picture

Below is what i'm using to connect and get the data, there's nothing there beyond that so far. Previously I've used some examples from the modern-carpentry website here: http://modern-carpentry.com/talk/?p=32 to build menus and pages. Its a great starting point but a bit messy. So i'd love to see some good examples of classes etc that output the data nicely.

<?php
//obviously this is as3 not php, but it colours it nicely this way
/**
* @description  Class to start the opie site
*/
package
{

   
import flash.display.MovieClip;
   
import flash.events.TimerEvent;
   
import flash.utils.Timer;

import com.thirdavedesign.drupalSite.DrupalSite;

 
import as3.utils.deepTrace;


  public class
opie extends MovieClip
   
{
      private var
drupal:DrupalSite;
     private var
gatewayUrl:String = "http://mysite.com/dev/services/amfphp/gateway.php";
     private var
apiKey:String = "the api key here";

     private var
TIMER:Timer;
      
       public function
opie()
     {
         
init();
        }
     
       private function
init():void
      
{
         
//connect to drupal
           
drupal = new DrupalSite(gatewayUrl, apiKey);
          
          
//look to see if we're connected - then go
           
TIMER = new Timer(400);
           
TIMER.addEventListener(TimerEvent.TIMER, getStarted);
         
TIMER.start();
     }
     
       private function
getStarted(ev:TimerEvent):void
       
{
          if (
drupal.CONNECTED)
          {
             
TIMER.stop();
             
drupal.getView('gallery', viewCallback, null, true);
            
trace("connected = " + drupal.CONNECTED);
            }
          else
           {
             
trace("connected = " + drupal.CONNECTED);
            }
      }
     
       private function
viewCallback(data:Object, view:Array):void
       
{
         
sortArticles(view);
        }

     private var
titles:Array = new Array;
     
       private function
sortArticles(result:Object):void {
           
           for (var
i = 0; i < result.length; i++) {
              
titles.push(result[i].title);
          }
         
          
deepTrace(titles);
        
       }
     
   }
}
?>

i'm using a deeptrace function to see whats going on:

<?php
package as3
.utils {
    public function
deepTrace( obj : *, level : int = 0 ) : void{
        var
tabs : String = "";
        for ( var
i : int = 0 ; i < level ; i++, tabs += "\t" );
       
        for ( var
prop : String in obj ){
           
trace( tabs + "[" + prop + "] -> " + obj[ prop ] );
           
deepTrace( obj[ prop ], level + 1 );
        }
    }
}
?>

the output is below:
DrupalSite
Alpha 0.5 - release/Public
8.27.2008
DrupalSite by Third Ave Design. Licensed under GPLv3.
Attempting to connect to AMFPHP interface...
connected = false
connected = false
Flash is connected to AMFPHP interface.
connected = true
[0] -> alex, bassist
[1] -> vienna
[2] -> basel
[3] -> art 3
[4] -> show
[5] -> Berlin
[6] -> boxes
[7] -> Miami
[8] -> tate
[9] -> new one
[10] -> Zurich
[11] -> window
[12] -> Portraits
[13] -> Arco
[14] -> artwork
cached data for view gallery

i've started a tutorial

amcc's picture

here's the beginnings of a tutorial
http://superfineshag.org/node/1

its got work to do, but should help people - please comment on it as i'd like to improve it and eventually get a good how to for druplash creation - the more people we can get going on this the more will get fed back into the druplash cauldron

The tutorial is great as a

ebeyrent's picture

The tutorial is great as a starting point, but what about when you need to call a custom service? The code below shows how to do that.

<?php
/**
* THIS IS AS3 CODE
*/
private function init():void{
 
// Build a dynamic path to your amfphp gateway
 
var protocol:String = ExternalInterface.call('location.protocol.toString');
  var
domain:String = ExternalInterface.call('location.hostname.toString');
  var
urlPath:String = ExternalInterface.call('eval', 'window.Drupal.settings.jstools.basePath');
  var
gatewayUrl:String = protocol + "//" + domain + urlPath + "services/amfphp";
  var
apiKey:String = '';
 
drupal = new DrupalSite(gatewayUrl, apiKey);
 
drupal.service(onSuccess, onError, 'custom_service.custom_method', [arg1, arg2]);
}

private function
onSuccess(data:Object):void{
 
// Do something with your returned data
}
?>

Cool! It would be so nice

jjjames's picture

Cool! It would be so nice though if there was a sample Flex mxml file that connects, logs in a user and saves a node through a form. Seems like it's taboo to connect to Drupal via Adobe Air. Anyone have any example code?

Thanks

shaman365@drupal.org's picture

Got this going with the services 6x-0.9, But using the new services 6-x.0.11, will generate errors when trying to use any DrupalSite methods like getView since the naming conventions for the service methods have changed.

Can't wait to start using this with the new services..............

Thanks again for this!

Do the naming conventions

FonzarelliDubsta's picture

Do the naming conventions have anything to do with the fact that "views.getView" is now "views.get"?
<a href="http://www.myspace.com/willywonkaakabeatbonkarz>Only local images are allowed.

mh load node

somes's picture

having problems getting a node to load any ideas where I can start debugging

i think the library is using node.load and the service should be node.get any ideas how i can debug
any one got any other code snippets on how to implement this

tks
M

been trying to get flash and drupal to work

somes's picture

what versions are compatible with what - there are several compatibility issues - also there are several flash libraies doing the rounds

is there any update on the integration with the latest services modules 6.13 ie node.get and node.load

any one any ideas

tks
M

passing arguments to views

amcc's picture

i'm slightly stumped on how to pass arguments to views using drupalsite - any hints?

modification to drupalsite framework to allow view arguments

amcc's picture

if you modify DrupalSite (version drupalsite-20080827) as below you'll be able to pass fields and arguments to your view

I've added two arrays which get passed as arguments to the startBlocking method: viewFields and viewArgs, for the fields and arguments options in the views service.

lines 332 to 353:

<?php
// This is AS3 - ignore this line
/**
     * Invokes the Drupal view.getView service method for retrieving nodes from a view.
     *
     * @param viewname Name of Drupal view to retrieve.
     * @param callback Callback function on success.
        * @param data [Optional] Data passed as argument to callback function.
     * @param reload [Optional] If set to true, then any cached data for the view is ignored,
       * and the view is reloaded from the Drupal site.
       *
     * @return Success (true) or failure (false) of blocking initiation.
        */
    
public function getView(viewname:String, callback:Function, data:Object = null, reload:Boolean = false, viewFields:Array = null, viewArgs:Array = null):Boolean {
         
           if (
VIEWS[viewname] && VIEWS[viewname] is Array && !reload) {
             
log('DrupalSite: info: Using cache data for view ' + viewname);
             
callback(data, VIEWS[viewname]);
               return
true;
           }
         
           return
startBlocking(callback, data, viewname, 'views.getView', viewname, viewFields, viewArgs);
        
       }
?>

Please comment if you feel there's a better way of doing this

Updated for compatibility with Services 6.x-0.13

arithmetric's picture

I've released a new version of our framework that works with Services version 6.x-0.13. Download the latest version from:
http://thirdavedesign.com/drupalsite

Due to inconsistencies among the versions of the Services module, this version of the framework will not work with Services for Drupal 5.x. Also, we have dropped automatic handling of API keys (disable 'Use keys' under Services >> Settings).

I haven't yet included artfo's modification to support Views fields and arguments, because the Views Services module actually doesn't support the field argument (see services/services/views_service/views_service.inc).

Whats the situations with

amcc's picture

Whats the situations with the current Service modules handling of API keys. I'm about to put a site online and i'm not sure of the security issues involved.

If the API key is included - could this also be a security issue - any flash file can be decompilied which makes the key accessible to anyone - whats the best method around this?

search.nodes service

amcc's picture

UPDATED - this function seems to work fine to use the search.nodes service, though there may be improvements that can be made.

@detour - Hi i'm trying to modify to your DrupalSite framework to add the search service, though i'm having some trouble. The search.nodes service works fine in the services admin area, but the code below simply repeatedly traces this message DrupalSite: info: Retrying service call search.nodes.

When i put in a search term into the services search.nodes page (/admin/build/services/browse/search.nodes) it works fine - returning two results.

here's the function i've added in DrupalSite.as:

<?php
/**
* Invokes the Drupal search.nodes service method for retrieving a node.

* @param search_keys Search Terms.
* @param callback Callback function on success.
* @param data [Optional] Data passed as argument to callback function.
*
* @return Success (true) or failure (false) of blocking initiation.
*/
public function searchNodes(search_keys:String, callback:Function, data:Object = null, reload:Boolean = false):Boolean {
 
   return
startBlocking(callback, data, search_keys, 'search.nodes', search_keys, true);
   
}
?>

I've tried with and without the optional simple call method (i.e. the true argument in startBlocking) - without flash hangs when i use a recursive trace function - so i'd set the simple argument to true - this gives the kind of results we're all used to anyway.

Permissions!

amcc's picture

Ah gets me everytime - I didn't turn on permissions for non-authenticated users to search. The above addition actually works fine - so if you want searching to work use it (also notice that I removed any caching code as i didn't think this was so relevant for searches). I find that if you don't set the simple argument to 'true' you get far too much data back with loads of repeated stuff.

using artfo's

seutje's picture

using artfo's modification:

faultString: Method <em>views.getView</em> does not exist.

changed

<?php
return startBlocking(callback, data, viewname, 'views.getView', viewname, viewFields, viewArgs);
?>

to

<?php
return startBlocking(callback, data, viewname, 'views.get', viewname, viewFields, viewArgs);
?>

to work with latest services and properly handle the argument, didn't try fields though

btw, DrupalSite() throws an Event.COMPLETE, so no need for a sloppy timer

<?php
           drupal
= new DrupalSite(gatewayUrl);
          
drupal.addEventListener(Event.COMPLETE, checkConnection);

     private function
checkConnection(e:*):void
    
{
         
drupal.removeEventListener(Event.COMPLETE, checkConnection);
           if (!
drupal.UID) {
            
buildLogin();
          }
          else {
             var
data:Object = new Object();
                var
flushCache:Boolean = new Boolean();
                var
fields:Array = new Array();
                var
args:Array = new Array();
             
flushCache = true;
            
args.push("someArgument");
              
drupal.getView("viewName", gotView, data, flushCache, fields, args);
         }
      }
?>

... etc

works like a charm, many thanks

although... I kinda edited it to default to not caching, as I'm used to just do the "caching" in my project and store everything in an object and crossreference with what's coming in

still, this helped me jump to AS3 lot easier than I figured, didn't feel liek rewriting my own classes q.q

@seutje

amcc's picture

@seutje yeah the bit I posted was for the drupal 5 version here:http://thirdavedesign.com/drupalsite

The best thing to do would be to download the drupal 6 version which is the latest one - then modify that method, here's my modification for drupalSite Version 2008/12/19 - (replaces lines 351 to 361):

<?php
public function getView(viewName:String, callback:Function, data:Object = null, reload:Boolean = false, viewFields:Array = null, viewArgs:Array = null):Boolean {
        
           if (
VIEWS[viewName] && VIEWS[viewName] is Array && !reload) {
             
log('DrupalSite: info: Using cache data for view ' + viewName);
             
callback(data, VIEWS[viewName]);
               return
true;
           }
         
           return
startBlocking(callback, data, viewName, 'views.get', viewName, viewFields, viewArgs);
        
       }
?>

To be honest this is probably out of date too as the Services module in D6 lets you pass a number of other arguments in addition to fields and args, so an update of this with fuller functionality would be in order.

yea, I started off from the

seutje's picture

yea, I started off from the D6 version, that's prolly why it bugged me about the views.getView :P

for now it does what I need it to, might add some stuff and change the caching to default to false

changed your framework a bit

seutje's picture

changed your framework a bit so that the COMPLETE event is always invoked when data is received and not only when system.connect was called so that I can always have the next service call wait till the previous one returns COMPLETE like so:

<?php
drupal
.getView("viewName", gotView, null, true, fields, args);
drupal.addEventListener(Event.COMPLETE, nextCall);

private function
gotView(data:Object, view:Object):void
{
   
// parse the view and do some magic
}

private function
nextCall(e:Event)
{
   
drupal.removeEventListener(Event.COMPLETE, nextCall);
   
drupal.getView("someOtherView", gotOtherView, null, true, fields, args);
   
drupal.addEventListener(Event.COMPLETE, someOtherCall);
}
?>

coz I noticed that when I put the next service call in the handler for the previous one, it doesn't always get run and sometimes runs into the blocked thingy, which is odd, because the blocking is removed when data is received... but this way seems pretty solid

but I think I'm gonna try to find a way to pass which call was made to the arguments of the events so I can use 1 big nextCall function with a switch case in it

could take me some more

tubage-gdo's picture

could take me some more demo? thanks

rolf vreijdenberger's picture

Hi,

To satisfy our own method of working with flash and as3, we've also released an opensource as3 drupal connection implementation.
It's part of a larger as3 toolkit/library of our company.

This one handles authentication keys and sessions and features all core services stuff.

check out an extensive blogpost including demo at http://www.dpdk.nl/opensource/drupalservice-as-a-bridge-between-flash-an...

Kind regards,

Rolf Vreijdenberger

drupal and flash: http://www.dpdk.nl/opensource/drupalproxy-as-a-bridge-between-flash-as3-...

Feedback

garphy's picture

That Drupal remoting API is pretty cool. I started to use it yesterday and noticed that the Menu service method is missing. I got to subclass DrupalService and DrupalEvent to add It (and it worked pretty well). I think you should add it in your base code as it's a core service module.

good idea

rolf vreijdenberger's picture

Hi Garphy,

great idea, we don't use it at the moment but it's easy to add. Will look into it, it'll probably be fixed tomorrow :)

thanks for the feedback!

Could you elaborate a bit on the subclassing? I added some hints in the comments so I guess you made a new instance of RemotingProxy, decided to override the error method to dispatch your custom (subclassed) DrupalEvent en subclass that. You should also override the destroy() method and in your constructor add some eventlisteners and callback handlers.
So I probably gave myself the answer to the question, but still, I'm curious :)

Kind regards,

Rolf Vreijdenberger

drupal and flash: http://www.dpdk.nl/opensource/drupalproxy-as-a-bridge-between-flash-as3-...

Re: good idea

garphy's picture

Yes, I subclassed (the word exists ? :) DrupalService to add a RemotingProxy for the menu service. I also subclassed DrupalEvent to add the result and error events. IMHO I found it a bit tedious as I can't use, for example, MyDrupalEvent.NODE_GET instead of DrupalEvent.NODE_GET and the code that use MyDrupalService has to manipulate the two class. I don't understand why adobe guys made static const inheritance not possible...

I does not digged in that deeply to find out i had to override destoy() but i'll look at your updated code.

Re:

garphy's picture

And just for information : it works.
I had to tweak a little bit your code at 3 places to be able to package it as an swc.
If you plan to distribute it and search for flex-mojos/maven/maven-repo expertise, don't hesitate to ask. For now, I'll repackage it and put it on my personnal repository.

Re:

rolf vreijdenberger's picture

aw man, thats s*cks.
I didn't realize that that is not possible. Just took it for granted. This was exactly what we had in mind, just inheriting the static properties already available in DrupalEvent.

That's what we made the error() method for in DrupalService, so you could use that by overriding and have it dispatch your CustomDrupalEvent (a variation on the factory method pattern)
Hmmm, the fix would be of course to not use the error() method, and just have your own callback handlers dispatch their own events, but this does mean that you would have to listen to both DrupalEvents and CustomDrupalEvents on your subclass (after reading your reply again I understand that's what you mean also)

So even though it's not as we would like to have it, subclassing and adding functionality is still possible.

any ideas on how to restructure this? we'll look into it as well...

more info about that here: http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhe...

Kind regards,

Rolf Vreijdenberger

drupal and flash: http://www.dpdk.nl/opensource/drupalproxy-as-a-bridge-between-flash-as3-...

actually...

rolf vreijdenberger's picture

I already fixed it.

it's tested, it works.
In DrupalUtils are some constants that can be used to get the right menu:

service.menuGet(DrupalUtils.MENU_NAVIGATION);

Kind regards,

Rolf Vreijdenberger

drupal and flash: http://www.dpdk.nl/opensource/drupalproxy-as-a-bridge-between-flash-as3-...

menu.got values

ventoline's picture

Apologis for the basic of the question, but I'm new to Drupal and don't do PHP -yet- so I'm a bit confused.

I managed to call my menu via "menu.get"; but how do get the values in the array?

function onConnectMenu(result:Object)
{
trace(result[0]["title"]); //??
trace( result.[0].title ); //??
trace ( result.Array[0]["title"]); //??

thanks for your patience..

Problem with retries

PWG's picture

Hi,

Thanks for a nice AS3/Drupal interface.

I've had some serious problems with the retry functionality (checkBlocking).

  1. The first problem I had was with the retry calls AND the original calls all calling the callback function (BLOCKING_FUNC). I fixed that by checking if the callback function had already been called before allowing onData to make the call to the callback function.

  2. The second problem is that retries for functions that insert/update/delete data can cause multiple - unwanted - updates of the database in spite of the fix in #1. The reason this problem occurs is that the call to the php function altering the data is called by both the original call and any retry calls, and I don't see any easy way to avoid this...Except to switch off retries altogether which is what I have done. I'm thinking of using retries for some functions only (such as system.connect) but I'm not sure that's the way to go...

If anyone has any input on #2, I'd be happy to hear it!

Cheers!

Services

Group organizers

Group categories

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: