who needs social life when you have broadband?

Inventas vitam iuvat excoluisse per artes / Let us improve life through science and art.

Flash and Joomla integration

One of the most requested things in the content management world is to make dynamic content to be displayed inside a flash movie. Flash has a feature that allows it to display content from a xml file, in this article I'm gonna explain how to display Joomla! content in your flash pages. With a little imagination you can change this "how-to" and make it work with other CMSes like Drupal, Xoops, or even your own CMS :-)

You can check a integration example accessing: http://www.mmoraes.com

Before we start:
- This is a script I wrote a while ago, it is probably not the best (or even the right) way to do this integration, but it works.
- You can use, change, set fire... do whatever you want with these classes but please keep my name and URL in the credits.
- Suggestions are always welcome :)

ok, let's roll

I'm not flash expert. In fact, I didn't even know how to program in ActionScript before my boss asked me to create this integration. All I knew is that Flash could "read" xml files. The logic to create the integration with Joomla! is pretty simple: Export Joomla!'s content in a way that the Flash movie can read it. This means that we will generate a dynamic xml file with whatever we want to export and create a .swf that accesses it and badda-bing!

In this proof-of-concept, I'm gonna export the menu items and create them dynamically in my movie. Ok, enough talking.

First step: My Array-to-XML class
Function: Convert any given array to xml. This class gives flexibility to adapt this technique to virtually any other CMS.

PHP:
  1. <?php
  2. /**
  3. * XML-Generator
  4. * @author Matheus Mendes aka bigodines - http://www.joomla.com.br
  5. * @date July, 2006
  6. * @license GNU GPL v2.0
  7. * @note: this class uses a different naming for each part of a xml:
  8. * <channel />
  9. *  <node />
  10. *   <item />attribute value</item>
  11. *   <attribute2 property="property value">item value</item2>
  12. *  </node>
  13. *  <node2 />
  14. *   <item />attribute value</attribute>
  15. *   <item2 property="property value">item value</item2>
  16. *  </node2>
  17. * </channel>
  18. *
  19. * I know these names aren't the standard. But that's the way i've learned :P suggestions are always welcome
  20. * -bigo
  21. */
  22.  
  23. class XmlGenerator {
  24.    
  25.     var $channel = null;
  26.     var $items = array();
  27.     var $nodes = array();
  28.     var $attributes = array();
  29.     var $xml = null;
  30.     var $level = null// indent helper
  31.     var $nodeName = null;
  32.  
  33.     function XmlGenerator($channel, $arrTree, $level = 0, $arrAttributes=null, $nodeName = "item" ) {      
  34.        
  35.         $this->nodeName = $nodeName;
  36.         $this->channel = $channel;
  37.         $this->level = $level;
  38.         if ( count( $arrTree ) <1) return;
  39.        
  40.         foreach( $arrTree as $name => $value) {
  41.             if (is_array( $value )) {            
  42.                     $this->addNode( $this->nodeName, $value, $level+1, $arrAttributes[$name] );               
  43.             } else {               
  44.                 if ($arrAttributes[$name]) {
  45.                     $this->attributes[$name] = $this->getAttributes($arrAttributes[$name]);
  46.                     $this->attributes[$name];
  47.                 }
  48.                 $this->addItem($name, $value );
  49.             }
  50.         }
  51.     }
  52.    
  53.        
  54.     function addNode( $channel, $arrAttribs, $level, $attributes=null ) {
  55.         $this->nodes[] = new XmlGenerator( $channel$arrAttribs, $level, $attributes );
  56.        
  57.     }
  58.    
  59.     function setNodeName($name) {
  60.         $this->nodeName = $name;       
  61.     }
  62.    
  63.     /* creates a new item */
  64.     function addItem($itemName, $itemValue ) {   
  65.         $this->items[$itemName] = $itemValue;
  66.     }
  67.    
  68.     /* transform an array into a string of attributes */
  69.     function getAttributes($arr) {
  70.         $attrString = "";
  71.         foreach( $arr as $k => $v) {
  72.             $attrString .= ' '.$k.'="'.$v.'"';
  73.         }
  74.         return $attrString;
  75.     }
  76.    
  77.     function getItems() {
  78.         return $this->items;
  79.     }
  80.    
  81.     function createXml() {
  82.        
  83.         //$this->insertHeader();
  84.         $this->insertBody();
  85.         return $this->getXml();
  86.     }
  87.    
  88.     function struct() {
  89.         echo "Items: <pre>"; print_r($this->items); "</pre>";
  90.         echo "Attributes: <pre>"; print_r($this->attributes); "</pre>";
  91.     }
  92.        
  93.     function insertBody() {
  94.        
  95.         $this->xml .= $this->tab($this->level) . "<" . $this->channel . ">\n";
  96.         foreach($this->items as $item => $value) {
  97.             $attribs = "";
  98.             if($this->attributes[$item]) {
  99.                 $attribs = $this->attributes[$item];
  100.             }
  101.             $this->xml .= $this->tab($this->level+1) . $this->toXml($item, $value, $attribs);
  102.         }
  103.         foreach( $this->nodes as $node) {
  104.             $node->insertBody();
  105.             $this->xml .= $node->getXml();
  106.         }
  107.         $this->xml .= $this->tab($this->level) ."</" . $this->channel . ">\n";
  108.        
  109.        
  110.     }
  111.    
  112.     function tab($level) {
  113.         $r = "";
  114.         for($i=0;$i<$level;$i++) $r .= " ";
  115.         return $r;
  116.     }
  117.    
  118.     function toXml($item, $value, $attribs=null) {
  119.         return "<" . $item . $attribs.">" . $value . "</" . $item . ">\n";
  120.     }
  121.    
  122.     function insertHeader($encoding = "utf-8") {
  123.         $this->xml .= "<?xml version=\"1.0\" encoding=\"".$encoding."\"?>\n";
  124.     }
  125.    
  126.     function getXml() {
  127.         return $this->xml;
  128.     }
  129.    
  130. }
  131.  
  132. //$xml = new XmlGenerator("mainmenu", $mainTree, 0, $attributes, 'nodezinho' );
  133. //echo $xml->createXml();
  134.  
  135. ?>

Second step: Create an export file that will be accessed by the flash movie
Function: We've gotta create one for each "part" we want to export (menus, news, polls, shopping items....). If you don't use Joomla! and uses another opensource CMS and has done (or are trying to...) this integration, please mail me so I can update this post :-)

Here we go:

PHP:
  1. <?php
  2. /**
  3. * Joomla! MainMenu using XmlGenerator
  4. * @author Matheus Mendes aka bigodines - http://www.joomla.com.br
  5. * @date July, 2006
  6. * @package xmlgen
  7. */
  8.  
  9. // begin - configuration
  10. $menutype = 'mainmenu';
  11.  
  12. // end - configuration
  13.  
  14.  
  15.  
  16. define('_VALID_MOS', 1);
  17. // joomla stuff :P
  18. include_once("../configuration.php");
  19. include_once("../includes/database.php");
  20. // XmlGenerator
  21. include_once("clsXmlGen.php");
  22.  
  23. $source = array();
  24.  
  25.  
  26. /* database object */
  27. $database = new database( $mosConfig_host, $mosConfig_user, $mosConfig_password, $mosConfig_db, $mosConfig_dbprefix );
  28.  
  29. $sql = "SELECT id, name, link, type, parent FROM #__menu " .
  30.         "\n WHERE menutype = '$menutype' " .
  31.         "\n AND published = 1 " .
  32.         "\n ORDER BY parent, ordering";
  33.        
  34. $database->setQuery($sql);
  35. $rows = $database->loadAssocList();
  36. // establish the hierarchy of the menu
  37. $familyTree = array();
  38. // first pass - collect children
  39. foreach ($rows as $v ) {
  40.     $pt = $v->parent;
  41.     $list1 = @$familyTree[$pt] ? $familyTree[$pt] : array();
  42.     array_push( $list1, $v );
  43.     $familyTree[$pt] = $list1;
  44. }      
  45.  
  46. //print_r($familyTree);  // debug
  47.  
  48. /* XmlGenerator params: channel, array with structure, start level, first node's name */
  49. $xml = new XmlGenerator("mainmenu", $familyTree, 0, null,'menuItems' );
  50. echo $xml->createXml();
  51.  
  52. ?>

Pretty simple isn't it? Basically, when this file is accessed, it collects our menu items and create a XML file using our XmlGenerator class.

Now, the final part: a Flash Movie to read everything.
As I said earlier, I'm no ActionScript developer neither a good designer. So this .fla may be VERY frustrating if you were expecting a lot of eye-candy effects or fancy colour combination :)

Actionscript:
  1. /**
  2. Creating a flash menu for Joomla! using XMLGenerator!
  3. @author Matheus Mendes aka bigodines - http://www.joomla.com.br
  4. @date july, 2006
  5. */
  6.  
  7. myXml = new XML();
  8. myXml.onLoad = XmlHandler;
  9. myXml.ignoreWhite = true;
  10. myXml.load("http://www.joomla.com.br/xmlgen/xgen-mainmenu.php");
  11. //myXml.load("test.xml ");
  12.  
  13. function XmlHandler(ok) {
  14.     if (ok == true) {
  15.         parseChannel(this.firstChild.firstChild); // parses the channel
  16.     }
  17. }
  18.  
  19. function parseChannel(channelNode) {
  20.     if (channelNode.nodeName.toUpperCase () == "MENUITEMS") {       
  21.         menuItem = channelNode.firstChild;
  22.         i=0;
  23.         while (menuItem != null) {
  24.             if (menuItem.nodeName.toUpperCase() != "ITEM") break;
  25.             id = "";
  26.             name = "";
  27.             link = "";
  28.             parent = "";
  29.             element = menuItem.firstChild;
  30.             while(element != null) {
  31.                 if (element.nodeName.toUpperCase() == "ID") {
  32.                     id = element.firstChild.nodeValue;                   
  33.                    
  34.                 }
  35.                 if ( element.nodeName.toUpperCase() == "NAME") {
  36.                     name = element.firstChild.nodeValue;
  37.                 }
  38.                 if (element.nodeName.toUpperCase() == "LINK") {
  39.                     link = element.firstChild.nodeValue;
  40.                 }
  41.                 if (element.nodeName.toUpperCase() == "PARENT") {
  42.                     parent = element.firstChild.nodeValue;
  43.                 }
  44.  
  45.                 element = element.nextSibling;
  46.             }
  47.             // do something!!
  48.             if (i <13) doSomething(id, name, link, parent, i++);
  49.             menuItem = menuItem.nextSibling;
  50.         } // while menuItem
  51.     } // nodeName == "MAINMENU"
  52. }
  53.  
  54. var nMenu_x = 80;
  55. var target = _root;
  56. var yPos = 60;   
  57.  
  58. function doSomething(id, name, link, parent, n) {   
  59.     myItem = target.attachMovie("myMenu", "menuitem"+n, 100+n);
  60.     myItem._x = nMenu_x;
  61.     myItem._y = yPos;
  62.     myItem.title = name;
  63.     myItem.onRelease = function() {
  64.         myItem.getURL('http://www.joomla.com.br/'+link , '_blank');
  65.     }
  66.     yPos += target["menuitem"+n]._height;
  67. }

You can download the .fla here

I hope it helps someone :)

-bigo

15 Comments so far

  1. FBI May 26th, 2007 5:49 pm

    OK, could you show an example of how content would be added using the xmlgenerator, say for the front page?

  2. bigodines May 26th, 2007 6:47 pm

    @FBI, you can check this website: http://www.mmoraes.com/templates/home/index-en.htm, as you can see, this is just a regular .htm (with flash, of course) that is including joomla content.

    you might note two things:
    1 - I’ve created a small hack to assign an image to each new. That image that you see in the News Scroll in the site I mentioned isn’t static. Its dynamic but just appears in the flash (objectively, it is just a new field to fill when the journalists insert news).
    2 - There is a bug with the nl2br() as you can see… If they insert content correctly (not hitting “enter” after the intro text) it would works well..

    BTW: The example in the article I wrote doesn’t have anything to do with the frontpage. As you may have noticed, it is a menu and a [really ugly] dynamic flash loader, but the principle is the same for every application.

    Cheers,
    bigo

  3. FBI May 27th, 2007 9:59 am

    Well, I don’t know the first thing about xml files. I do understand some php and flash action script. Could the export file you have stated above (for the menu) be modified for news, polls, and whatnot? Or would the coding be different for each section I would want to export? For example, if changed

    // begin - configuration

    $menutype = ‘mainmenu’;

    // end - configuration

    and

    $sql = “SELECT id, name, link, type, parent FROM #__menu ” .

    “\n WHERE menutype = ‘$menutype’ ” .

    “\n AND published = 1 ” .

    “\n ORDER BY parent, ordering”;

    to news where ($menutype = ‘mainmenu’;)=($contenttype = ‘news’;)

    and

    $sql = “SELECT id, name, link, type, parent FROM #__menu ” .

    “\n WHERE menutype = ‘$menutype’ ” .

    “\n AND published = 1 ” .

    “\n ORDER BY parent, ordering”;

    is changed to

    $sql = “SELECT id, name, link, type, parent FROM #__content” .

    “\n WHERE contenttype = ‘$contenttype’ ” .

    “\n AND published = 1 ” .

    “\n ORDER BY parent, ordering”;

    would this work? Would you be willing to post an example script for an export file for use with news? I seem to learn better when I can see how it should look and then work backwards (reverse engineer as some would say) the script to see how it interacts with on another.

    Thanks

  4. bigodines May 27th, 2007 10:16 am

    The XmlGenerator class will work without modifications converting any given array to an XML file, so if you want to export different parts of your joomla, you will need to create files that use this class. These files will generate arrays with the info you would like to convert to XML and then you pass the generated XML to the flash.

    I’ll try to find some time this week to blog a different example exporting something else. but the principles are the same.

    cheers,
    bigo

  5. FBI May 27th, 2007 10:44 am

    setQuery($sql);
    $rows = $database->loadAssocList();

    // establish the hierarchy of the menu
    $familyTree = array();

    // first pass - collect children
    foreach ($rows as $v ) {
    $pt = $v->parent;
    $list1 = @$familyTree[$pt] ? $familyTree[$pt] : array();
    array_push( $list1, $v );
    $familyTree[$pt] = $list1;
    }

    //print_r($familyTree); // debug
    /* XmlGenerator params: channel, array with structure, start level, first node’s name */
    $xml = new XmlGenerator(”news”, $familyTree, 0, null,’contentItems’ );
    echo $xml->createXml();
    ?>

    sorry, code didn’t come out right.

  6. bigodines May 27th, 2007 10:49 am

    there’s an easier way. I’ll blog (will write right now) an example and post here to show you. (inserting code as comments is pretty buggy in wp :/

  7. FBI May 27th, 2007 10:49 am

    ok, one more try with the coding.
    setQuery($sql);
    $rows = $database->loadAssocList();

    // establish the hierarchy of the menu
    $familyTree = array();

    // first pass - collect children
    foreach ($rows as $v ) {
    $pt = $v->parent;
    $list1 = @$familyTree[$pt] ? $familyTree[$pt] : array();
    array_push( $list1, $v );
    $familyTree[$pt] = $list1;
    }

    //print_r($familyTree); // debug
    /* XmlGenerator params: channel, array with structure, start level, first node’s name */
    $xml = new XmlGenerator(”news”, $familyTree, 0, null,’contentItems’ );
    echo $xml->createXml();
    ?>

    If this dosen’t show then the site won’t allow me to post the full code.

  8. FBI May 27th, 2007 10:50 am

    oh, ok. sorry for all the posts.

  9. […] how easy is to export Joomla! content to a XML format and then use it inside your flash movies (as you learned in the first part of this “article”). Today I’m gonna show a quick-and-dirty way to export your frontpage […]

  10. santiago June 11th, 2007 2:34 pm

    hello, I’m trying to test this tutorial, but I can’t see the menuitems.. If I test the xml via webbrowser in a joomla localhost site, I get the items, but when I try to see them trough flash, they just don’t appear.. After some “trace”, It seems that the problem is in the actionscript. Here: if (channelNode.nodeName.toUpperCase() == “MENUITEMS”) {

    .. It doesn’t recognize the “MENUITEMS”.. don’t kwnow why….

    I did this test:
    if (channelNode.nodeName.toUpperCase() != “MENUITEMS”) {
    trace (”yes”);
    }
    /* and I do get a trace …*/

    if (channelNode.nodeName.toUpperCase() == “MENUITEMS”) {
    trace (”yes”);
    }
    /* and I do NOT get a trace …*/

    please If anyone know what is going on, I would appreciate a lot… thanx..

  11. emurhfkq June 21st, 2007 2:11 pm

    people are stranger

  12. Ryan August 3rd, 2007 4:15 pm

    For anyone trying to figure this out here is how to do it.

    I had troubles because the directions are slightly vague but once I figured it out it was clear. The content example worked right away but this one did not.

    I used a macro to remove all the numbers in the code above with TextPad… quick and easy.

    1. Create a new directory in your Joomla root directory called xmlgen

    2. First chunk of code above, put it in a file called clsXmlGen.php and save it into your Joomla/xmlgen directory.

    3. Second chunk of code above, put it in a file called xgen-mainmenu.php and save it into your Joomla/xmlgen directory.

    4. Third chunk of code above, just ignore that and download the .fla file below it.

    5. Open up the .fla file in Flash and change line 10 to point to your xmlgen/xgen-mainmenu.php file.

    6. On line 64 update the URL to your Joomla site including trailing slash.

    7. On line 64 you will probably want to change _blank to _self so it doesn’t open in a new window every time.

    8. Export the Flash movie and add the code to call the Flash file to your template or use a module to show the flash. There are some free ones on the extensions.joomla.org site.

    Now, if everything went well, you should have a crude lookin menu that you can customize by editing the Flash file :)

  13. Ryan August 5th, 2007 9:37 am

    I realized that on line 64 in step 6 above you should also add the Itemid as well so it detects permissions and whatnot properly. So to use the one above for an example on line 64 you would add the Itemid like the following:

    #
    myItem.getURL(’http://www.joomla.com.br/’+link+”&Itemid=”+id , ‘_self’);
    #

  14. Sander January 18th, 2008 10:54 am

    I whanna use this for joomla 1.5 but i can’t get it to work can you help me out?

  15. Remy November 10th, 2008 12:31 pm

    This does work but its only for a menu, is it also possible to show content in a swf??

Leave a reply