I Built a Joomla Component with Haxe

Tank on Mountain

Here is my code, and that’s me at the top of the mountain there, wondering what to do next.

In case you didn’t know, my favourite programming language Haxe compiles to PHP, and my favourite CMS Joomla is made with PHP. I’ve been longing for a robust user-friendly CMS done in Haxe for some time, but it’s been long in coming. So I built this Joomla component with Haxe by following the Joomla Project’s component tutorial, converting to Haxe as I went along. As far as I know, I’m the first person to ever do this so I’m somewhat pumped about that. I’m here to tell you what I learned and hopefully it benefits somebody.

The Compiler

If you browse my code, the first thing you might look at is the php.hxml file, which configures the compiler. You will notice that this file is very lengthy. This is due to the fact that when Haxe compiles a PHP project it creates a single PHP entry point which links to the specified main class. All the classes are filed away in a “lib” directory as separate files. This is great if you’re building your own stand-alone application, but Joomla is very prescriptive in the way components need to be structured. If you want to take advantage of the CMS’ advanced features such as template overrides and its built-in MVC system, you need to follow strict conventions in class naming, file naming and folder structure. I can’t explain all that here, but I’ve made a few comments in my code about it. You will learn from my php.hxml file that:

  • I have separate “main” class files which will cause Haxe to compile the files which Joomla needs, using the “–php-front” compiler option to specify the proper file name, and “–php-lib” option to ensure Haxe files its own stuff in a single lib location.
  • Even though I could specify the file name of the php entry point, I had little control over the code it contained. Haxe always generates a call to the constructor function which conflicts with what Joomla does, so I needed to search/replace that line with a simple include of the desired class. I used the “-cmd” option to call a PERL command which does the job easy and quick without needing a Haxe macro.
  • To make life easier I also included other -cmd options which remove ‘.DS_Store’ files on Mac (don’t want those on live site), copy the generated files from my development folder to my local server folder, and zip-compress the component for easy installation in Joomla.

If I had better skill at using macros I might look into better ways of generating the required files, but this seems to work for now.

Externs

The great thing about Haxe is that by using externs you can refer to non-Haxe classes without the compiler complaining. This is essential when developing for an existing PHP framework. Unfortunately these are very time-consuming to create by hand, so I relied on a couple different tools for generating these:

  1. Macro: A great macro by Samuel Batista (found in files called “PHP.hx”). I modified it to use an external configuration for file paths. In most cases I was able to generate a good extern by using a build directive at the top of a class which called the “generateExtern” function in the macro. To give the macro something to process, I needed to copy Joomla’s “libraries” directory into my own code folder. This made it easy for me to manually remove things like comments which interfered with the macro, and will prevent Joomla updates from breaking anything.
  2. Convertor: The PHP-to-Haxe conversion tool here. When the #1 macro was proving too troublesome, I would simple copy/paste the Joomla PHP class into the convertor in #2 above, and then hand-edit the results (see my externs for JObject, JRequest, JTable and JToolbarHelper).

As I discovered Joomla classes I needed to access, I would need to locate them in the Joomla libraries directory and then create the externs using the above methods.

Non-Haxe Stuff I Did

I could likely make a case for developing in Haxe rather than PHP in many circumstances, but it’s just not a good substitute for creating HTML, SQL, XML, or INI language translation files. There are also PHP files in the tmpl directories which are intended to be overridden by the user and so should be easy to read. These also need to follow naming conventions, so I chose to simply hand-code that PHP directly. JavaScript files might have been good candidates for using Haxe, if I had needed any complex ones.

Random Tips on Developing with Haxe for Joomla/PHP

The Joomla Project’s component tutorial was thorough but unfortunately written for Joomla 2.5 rather than 3.0+ at the time of this writing. When things weren’t working right, I usually had to refer to the php_error.log file to see what happened. I use MAMP on my Mac, which makes it easy to locate that file and open it using the Mac’s Console application. Once I knew where the error was, I would then open the offending PHP class to see if my Haxe code had generated the code I wanted. When an error was generated by Joomla rather than PHP, it would usually appear onscreen instead of within the log.

I would often use Haxe’s “untyped __php__” feature just to get things working, then convert that to pure Haxe once I knew it could work properly. I left some php commands as untyped because I wasn’t sure how to replicate them in Haxe easily.

I included cache directories in the component because Haxe will use them after the component is installed.

PHP Arrays do not automatically become Haxe arrays, and vice versa. When Joomla is feeding an array into one of your functions you may need to convert it using “toHaxeArray” from the php.Lib.

This component is missing some of Joomla’s built-in goodies such as ACL, trashing, and batch operations. I really just wanted a working component to show it could be done. I highly recommend becoming a Joomla expert before using this code for anything important.

All PHP code installed in Joomla needs to use a GPL license and needs to refer to it within the code. This would need to be added if you wanted to make something for the Joomla Extensions Directory. Your Haxe code can use other licenses because it would qualify as a “Tool”.

Where to go now?

I have dreams of making Joomla components with a complex front-end using OpenFL, and it would be nice to have a user-friendly backend for easy administration. Joomla includes good tools for producing JSON output and using XML-RPC, so that’s what I would rely upon if I ever went further with that idea.

Ideally I would want a Haxe Joomla development tool to have an easy configuration method that would generate all of the required Joomla files automatically such as this ant script does. Even better would be to have a rapid application development framework like Akeeba FOF. Unless I start doing lots of Joomla components this way, I doubt that this would happen.

As for now, I have climbed the mountain and am looking for a suitable target I can shoot from this vantage point. I hope my tank doesn’t get too rusty before the war starts.

Making Things Last

I have an oil painting hanging in my home—a landscape of a lake reflecting the sunset that burns beyond a far-off mountain. I know enough about art to know that it is mediocre in terms of execution, style and composition. However I love the painting dearly because whenever I see it I am reminded of my grandmother who painted it.

Oil Painting by Jean Dowdeswell
Oil Painting by Jean Dowdeswell

I reflect on this and wonder what my children will have to remember me by. I dabble in music, poetry, writing, photography, illustration and artwork. I’ve produced a lot of things professionally over the years in both graphic design and programming. Yet a large percentage of my stuff is in digital form, and this worries me a bit. I see these problems:

  1. Storage media becomes obsolete and incompatible much too rapidly, and it deteriorates over time.
  2. File formats, especially interactive media, also become obsolete very rapidly.
  3. Online storage services aren’t bulletproof and access can be lost due to human error.
  4. If I die, who will be willing and able to track down all of this stuff I’ve stored in various places?

Right now, my solution to the above problems is eclectic. I try to keep most stuff on my one computer and to keep a reliable hard drive backup. Right after I’m done this article, I intend to review whatever instructions are left for accessing this and my other things which are stored online. Just like I told myself last year. And every year before.

What about code?

I will admit that when I write code, my primary goal is for it to be useful right now for the task at hand. I can’t help but wonder however whether my code will be useful many year from now.

If you follow me on Twitter for any length of time you will soon learn that I am an advocate of the Haxe language. It has been around for ten years now, and although it isn’t extremely popular, it is extremely versatile and can be compiled not only for multiple platforms but also multiple other languages.

In a nutshell, I see that code written in Haxe is going to have a very strong likelihood of being useful many years from now, no matter what other technologies come along.

But let’s gain a larger perspective on these issues:

Does any of this matter, and will anyone care?

I went to a presentation by Stefan Sagmeister a few months ago, and he talked a lot about happiness. He had some good insights about how to be happy, but it left me wondering: is that what life is about? Does it do any good to pursue happiness during this lifetime when it is just a speck on the timeline of eternity? His show was preceded by a presentation by the wonderfully talented Brian Kachur who made the point that creative people need to spend less time worrying or grumping, and more time making “cool shit”. That resonated with me a bit more than Stefan’s presentation, and it got me reflecting more on the meaning of it all.

Why is stuff cool? It seems to me that it’s about the audience and not yourself. I’ve joked before that I can be cool all by myself at home, but I don’t really believe it. Something is cool because it is judged to be so by others. We have a relationship with and obligation to the audience of whatever we make. I also believe that when we are focused on serving others, we are more likely to forget our own problems and therefore more likely to be happy. But happiness must not be the end goal.

Because it can entertain and inspire, communication design is an opportunity to do good. It is being good that will make people remember you and love you. That’s why I love my grandmother’s painting—it is because I loved her and it helps me remember her.

I want to take this idea yet another step further. I mentioned about our audience judging our works to be cool or good. Will we have the same audience many generations from now? I think about how much I know about my great-great-grandparents and I have to answer no. There is only one judge left after that amount of time, and I know my works will be remembered and written in his book forever. With no data loss.

How to force Firefox, Chrome and Safari for Mac to display scrollbars

Since OS X Lion came out, Macs have had the strange habit of making scrollbars disappear when an HTML div element is overflowing but not actively scrolling. This puzzles me because usually Macs are great for user interface improvements, and this is a step backward in my opinion. Sure, Mac users have the option of re-enabling the scroll behaviour, but web developers want to make sure people know to scroll.

There is no cross-browser way of fixing this with just CSS according to my research, so I came up with this solution using JavaScript:

First, use this CSS to make sure your div is set to show scrollbars:


.mydiv{ overflow-y:auto; }

Then attach this script to your page (this requires JQuery).

var sc;
jQuery(document).ready(function(){
	//constantly update the scroll position:
	sc=setInterval(scrollDown,200);

	//optional:stop the updating if it gets a click
	jQuery('.mydiv').mousedown(function(e){
		clearInterval(sc);            
	});
});
function scrollDown(){
	for(i=0;i<=jQuery('.mydiv').length;i++){
		try{
		var g=jQuery('.mydiv')[i];
		g.scrollTop+=1;
		g.scrollTop-=1;
		} catch(e){
		//eliminates errors when no scroll is needed
		}
	}
}

Purists may object to using a JavaScript loop in this way. Sorry, but sometimes when you want bacon you have to butcher a pig. 🙂