Image from akashicreading.com
Why Joomla! needs both a Framework and a Platform
Hugo Azevedo 1,253

J4 essay - Why Joomla! needs both a Framework and a Platform

Note: This document is part of a set of documents which constitute an essay about what Joomla! is, or can be in the future. These documents do not constitute the current state of Joomla!'s development, nor are they just rants or brain dumps. They list a set of structured ideas about what Joomla! can be, and provide some ideas on how to get there. Their main purpose is to generate discussion over Joomla!'s community.

If you have been a Joomla! User, Developer, Site Builder and/or Contributor for some time, and you know a bit of Joomla!'s history, then you know there were, at least, two attempts of separating Joomla!'s mechanics from its final product, the CMS. They were called Joomla! Framework and Joomla! Platform.

A while back, I tried to find out their history and purpose, to almost no success. I do know that the Framework was the first to be created, and became its own "product". The main idea behind this, was to allow developers to build other web applications unrelated to the CMS, using the same core functionality. Along the way, the Framework and CMS drifted apart, becoming completely unrelated products (might need some fact checking), so a Platform was created with the same intent, only to be canceled after only two years.

The general idea, is to have a multi-purpose Framework, like many others out there, that could be used as the "skeleton" and/or "engine" for the CMS, that in turn, would sit on top of it.

Today, it seams that the Framework project is awaken once again, with the same intent of working as a base for the CMS, although, I recently saw a video of a core production team member stating that the CMS was returning (if it ever left) to its monolithic/holistic approach. This for me, is going in the wrong direction.

Today, Joomla! seams to be too focused on the end user, who ever he/she is, and by doing do, is discarding a big chunk of the market.

By focusing on the CMS, and trying to please every single end-user out there, which is an impossible task and the PLT knows it, Joomla! actually becomes unappealing to everyone.

Apart from a personal preference, how would you sell Joomla! as the best fit for the corporate world, or to another developer and/or designer, instead of another solution? That's a hard task!

So, why the need of a Framework and/or Platform?

Well, the need actually comes from the market. There's a big demand for developers using Zend, Symphony, Laravel or Rails (among others), and the demand for CMS's (apart from WP), seams to be in decline. This alone, should be a subject of reflection by Joomla!'s community.

Developers look for Frameworks, to speed up their productivity. They use them to avoid having to do all those routine tasks and setups every time they begin a new project. If you hear David Heinemeier Hansson talk about why he created Rails, you will hear him say exactly that. But at the same time, developers want to maintain control over their development, and scale it as much as they want, and however they want.

Joomla!'s back-end is very good, and Joomla! is very extensible, uses standard market development patterns, and is very stable, so why can't it compete with Frameworks in the market place? The answer might be simple. Joomla! is neither fish nor fowl! It's something in between. I can't fully compete in simple websites with its nemesis (we all know who it is), nor it can be the best corporate solution, even if it can deliver very well in both environments.

What I'm about to say might sound shocking, but in my opinion, Joomla! should stop being a CMS all together. Let me explain!

Imagine that Joomla! is actually a set of only two products, one on top of the other, with no defined specific purpose. Could be a CMS, or it could be something else. Lets call these two products a Framework and a Platform for now. The purposes of both products would be different, even if one relied on the other. The Framework would work like the wooden-frame on the base of a wooden-frame house, and the Platform as the floor boards on top of that wooden-frame. They don't define the shape nor size of the house, but they act as the building blocks for it.

This would mean a completely different shift from Joomla!'s current philosophy (CMS based), and the main argument against this approach would be, that Joomla! would need to be completely rewritten, taking too much time and effort to do so. The funniest part is, this is not true. This wouldn't imply a complete Joomla!'s rewrite (to a certain extend). Most of Joomla!'s libraries and classes would still be reused (only differently), and the minor changes they would need (ex:. Namespaces…) are already scheduled for J4.

Joomla! Framework

On the bottom/base, you would have a Framework. The Framework doesn't really need to be called a Framework, and to avoid confusion to people coming from other frameworks, it should be named something else. We could call it “Engine”, or something like “The Construct” (like in the Matrix). If you recall The Matrix, the Construct was a base program on which the Matrix ran. Morpheus also used it to load Neo's training fight programs, and from what I recall, it was also used for weapons loading. To keep this on the serious side, I'll just call Joomla!'s base layer, the Engine.

Matrix Construct

 

Like the name states, the Engine would act as the engine for Joomla!. So, keeping this in mind, the Engine would be responsible for all of Joomla!'s mechanics, and it should remain output agnostic and lightweight. Although not limited to, these could be its main responsibilities:

 In order to keep the Engine extensible, the main application object should be event driven, and work as a dispatcher to other objects/functionality.

Lets face it. There is a sequence/order while processing a web request, and this sequence involves an ordered set of steps that start with the user's request, and ends with the server's response. By making this sequence open, and making it possible to insert more steps in the sequence, the Engine can easily be extended with, lest say, a Platform on top of it.

Imagine the following (simplified) execution sequence:

 Now, imagine a simple main application engine's class definition like this:

<?php

final class Engine
{
    public function addEvent($name, $after = null);
    public function addEventHandler($event, $handler);
    public function execute();

    private function callEventHandler($eventHandler);
}

The full class definition could be something like the following:

Note: Keep in mind that the following code was not tested nor finished, and should only be seen as an example.

<?php

/**
 * Engine processing class.
 *
 * @author    Hugo Rafael Azevedo
 * @version   1.0.0
 * @since     1.0.0
 */
final class Engine
{
    /**
     * @var  array  $events  List of available events for the execution's cicle.
     */
    private $events = null;

    /**
     * @var  array  $eventHandlers  List of event handling functions for each of the available events.
     */
    private $eventHandlers = null;

    /**
     * Initializes Engine object.
     * Adds all initial Engine's events, and corresponding initial event handlers.
     */
    public function __construct()
    {
        // Creates event related lists.
        $events        = array();
        $eventHandlers = array();

        /**
         * Starts loading initial event list, and corresponding event handlers.
         * This will be an initial list, that can be expanded during the application's execution.
         * 
         * The actual task, is the first event handler on the corresponding onAfter event.
         * This way, any onBefore event handler will always execute before the actual task,
         * and every onAfter event handler will always execute after the actual task.
         */
        $this->addEvent("onAfterRequest");
        $this->addEventHandler("onAfterRequest", "first.initial.after.request.task");

        $this->addEvent("onBeforeSessionLoad");
        $this->addEvent("onAfterSessionLoad");
        $this->addEventHandler("onAfterSessionLoad", "first.task.that.actually.loads.session");

        $this->addEvent("onBeforeDatabaseConnection");
        $this->addEvent("onAfterDatabaseConnection");
        $this->addEventHandler("onAfterDatabaseConnection", "first.task.that.actually.connects.to.database");

        $this->addEvent("onBeforeUserProfileLoad");
        $this->addEvent("onAfterUserProfileLoad");
        $this->addEventHandler("onAfterUserProfileLoad", "first.task.that.actually.loads.user.profile");

        $this->addEvent("onBeforeExecuteContent");
        $this->addEvent("onAfterExecuteContent");
        $this->addEventHandler("onAfterExecuteContent", "first.task.that.actually.executes.content");

        $this->addEvent("onBeforeResponse");
        $this->addEvent("onAfterResponse");
        $this->addEventHandler("onAfterResponse", "first.task.that.actually.returns.content");

        $this->addEvent("onBeforeClearResources");
        $this->addEvent("onAfterClearResources");
        $this->addEventHandler("onAfterClearResources", "first.task.that.actually.clears.resources");
    }

    /**
     * Adds a new event to the event list.
     * 
     * @param  string    $name   Name of the event to add to the list
     * @param  string    $after  Name of an event, after which the new event will be added. If NULL, will add new event to end of list.
     * @throws Exception
     * @return void
     */
    public function addEvent($name, $after = null)
    {
        // Checks if event's name is filled.
        if ($name == null || strlen(trim($name)) == 0)
            throw new Exception("Invalid parameters. Event name can't be empty.");

        // Standardize event's name.
        $name = strtolower(trim($name));

        // Check if event is to be added at the end of the execution cicle.
        if ($after == null || strlen(trim($after)) == 0)
            array_push($this->events, $name);
        else
        {
            // Standardize previous event's name, and checks if it is filled. 
            $after = strtolower(trim($after));
            if (($key = array_search($after, $this->events)) !== false)
            {
                // Inserts new event after previously found event.
                array_splice($this->events, $key, 0, $name);
            } else {
                throw new Exception("Invalid parameter. No event found.");
            }
        }

        // Adds an empty array to the event's eventHandler list.
        $this->eventHandler[$name] = array();
    }

    /**
     * Adds a new event handler to an already created event.
     * 
     * @param  string    $event    Name of the event for which a new event handler will be added.
     * @param  string    $handler  Name of the event handler to be added. 
     * @throws Exception
     * @return void
     */
    public function addEventHandler($event, $handler)
    {
        // Checks if parameters are filled.
        if ($event == null  ||
            $handler == null ||
            strlen(trim($event)) == 0 ||
            strlen(trim($handler)) == 0)
            throw new Exception("Invalid parameters. Event and Eventhandler names can't be empty.");

        // Checks if provided event exists.
        if (array_search($event, $this->events) === false)
            throw new Exception("Invalid parameter. No event found.");

        // Inserts new event handler in list.
        // New event handlers will always be added to the end of the event handlers list, for the specified event.
        array_push($this->eventHandlers[$event], $handler);
    }

    /**
     * Executes all Engine's events.
     * 
     * @return void
     */
    public function execute()
    {
        // Initializes control variable.
        $step = 0;

        // Loops until the execution step is out of the array's scope.
        // During event execution, new events might be added to the list, so this count needs to be updated for each iteration.
        // If the step exits the list boundaries, execution exits the loop.
        while ($step <= count($this->events))
        {
            // Collect current event for execution.
            $event = $this->events[$step];
			
            // Loop through all the event handlers associated with current event.
            foreach ($this->eventHandler[$name] AS $eventHandler)
                $this->callEventHandler($eventHandler);

            // Event processing is finished. Update execution step.
            $step++;
        }
    }

    /**
     * Does all the processing necessary to reflect call the specified method.
     * Implementation not needed for example.
     * 
     * @param  string  $eventHandler  Path to eventHandler method
     */
    private function callEventHandler($eventHandler)
    {
        // TODO: Verify path to, and include eventHandler's file.
        // TODO: Initialize necessary object(s).
        // TODO: Execute method using reflection.
    }
}

This Engine object could be executed using only two lines of code, and could easily be extended:

<?php
// Engine's simple execution.
$engine = new Engine();
$engine->execute();

/**
 * Could also be extended, even in executing events.
 * Here, similar Joomla!'s syntax was used.
* * First, we'll declare a class that will be executed before the content gets processed.
* In the middle of that event's execution, we will add a new eventHandler to another class,
* therefore extending the application's functionality. */ class exampleClass { public function testMethod() { // Get Application object, and add a new Handler in the middle of the execution. $app = \Path\To\Joomla\Application\Object\JApplication::getEngine(); $app->addEventHandler("onAfterExecuteContent", "\Namespace\Path\To\Another\Class\secondClass.anotherMethod"); // Outputs a string. echo "exampleClass.testMethod(); \n"; } } // Adds a second class to be executed. class secondClass { public function anotherMethod() { // Outputs a string. echo "secondClass.anotherMethod(); \n"; } } // Initializes the engine, and executes it. $engine = \Path\To\Joomla\Application\Object\JApplication::getEngine(); // Add a Handler "exampleClass->testMethod()" to be executed before the main content. $engine->addEventHandler("onBeforeExecuteContent", "\Path\To\First\Class\exampleClass.testMethod"); $engine->execute();

The previous code will output the following:

// (Enters the onBeforeExecuteContent event)
outputs: exampleClass.testMethod();
// (Enters the onAfterExecuteContent event)
// Processes main content.
outputs: secondClass.anotherMethod();

The Engine should also include an auto-load directory, where other (big) blocks of code that don't fit an extension definition, could be included/plugged in. Ex:. The Platform.

The main benefit of this approach, is that the developer could now have access to a lightweight product, stripped down to the bone, that could be used for webservices or for CLI automated tasks, or even for example, the base implementation for a Joomla! update server, without the overkill of having all of Joomla! installed.

All the initial events from the Engine would have to be published in Joomla!'s website, so that developers would know the the application's flow before hand. Not only event driven system is very easy to understand, but it can also provide the developers a very good starting point to any kind of product they wish to develop. Since it is event driven, and together with an autoload functionality, it can easily be extended to any number of executing tasks.

The Engine itself, would use its own events to load any other classes it would need to perform. For example, the Engine could use its own onAfterRequest (which is the first executing event), and attach an event handler to it that would initialize the current JFactory object. By the time the Engine processes the second event in the list (onBeforeSessionLoad), it will already have JFactory at its disposal.

Joomla! Platform

As said previously, the Engine would be format agnostic, and its main purpose would be to set the environment for a single task execution (request/response), returning its content. Therefore, it wouldn't deal with all the overhead related to web applications. This is where the Platform would come in.

Joomla!'s Platform could be seen as a Framework on top of another Framework, but with a specific purpose, Web Application Development. It would be dependent on the Engine, introduce UI (html) specific functionality, and it should allow the development of infinite applications, that would share the same resources (ex:. filesystem, database, js files, css files, images, documents, etc.). Joomla!'s Platform would be the one responsible for bringing Templates, Modules or code Snippets to the solution (or any other UI specific functionality).

The Platform would use the autoload functionality, to plug its own set of events around the Engine's event list, and therefore, extending the Engine's functionality from within. Component developers could also use the event driven mechanism to plugin/attach any necessary task to existing events, for example, logging, changing the application's buffer information, etc... Instead of having external plugin extensions, the developers could link directly to a Controller's method, but that's for another discussion.

By allowing infinite applications to run on top of the Platform, the developer/site builder could have just one application (front-end editing), two applications (front-end and admin), or have several applications in the same solution, each identified by an application id (like nowadays).

The entry point for each application shouldn't matter as well. This means that, the site builder could have an admin panel in a subdomain of the front-end, or in a completely different domain all together, as long as, they shared the same filesystem, database and resources. Therefore, the administrator's location could be easily obfuscated, which would allow for separate server traffic logs as well.

The truth is, this could already be done today, by tweaking 2 or 3 core extensions, and changing both application's entry files, although, other extensions (core ones included) would break down the line.

Joomla! Platform would also have to deliver fully featured, SEO ready, Multi-lingual, Social Media integrated, and fully standard compliant markup web application for the client. It would also had to facilitate front-end frameworks integration. One thing that didn't made much sense to me, when starting to use Joomla!, was the fact that I had to extend it via plug-ins, just to have SEF urls working in a website, and in the end, that would only guarantee a good implementation on core extensions, not 3rd party ones. If you wanted meta-tags, you would need to override everything, and include them in the Views, and not in the Models (assuming that's part of the business logic).

What about the CMS?

This is the best part. By making Joomla! a Platform on top of an Engine, the CMS would be just a possible implementation for Joomla!, and not Joomla! itself. It would work as a Distro works in Linux's universe, which would give Joomla!'s users loads of benefits.

Firstly, there would be almost no “core” extensions, and every “core-system” extension (opposing to “core-content” extensions), would only work as UIs for available functionality, either in the Engine or Platform. Every extension would be decoupled from Joomla!, which means that even if it came with a Joomla! implementation, you could still uninstall or reinstall it whenever you wanted, including “core-content” extensions. This would allow to replace every single extension that might come with a Joomla! CMS implementation, which would make, literally, a perfect fit for everyone.

You could have a Joomla! distro, with a simplified article management component, that could be perfect/simple for bloggers, but you could also have another distro, with a fully fledged article management component for the more demanding user (ex:. Newspaper).

Overall system benefits

There are several benefits that might come out from this approach, some direct and some indirect, but the main ones are related to the separation of concerns.

By separating everything, you are creating different products, that can be maintained separately, and with different production cycles. You wouldn't need to update the whole CMS system, and increment its version number for a minor fix in the Engine. You would just update the Engine, and possibly, everything on top would remain the same. Engine and Platform would have different release cycles, and could be supported for far more time (LTS), because in reality, they would never stop being supported.

By being decoupled, content extensions (articles, categories, menus, etc…) would also get developed independently. By releasing an update for the Platform, that wouldn't mean necessarily that the content extension would need to change, and vice-versa.

As a conclusion, everything would be much more manageable.

So what happens to the current versions numbers, for example, for the CMS? Well, they would disappear. The CMS implementation would then become a once a year release product, and would only contain a fresh install of a predefined set of extensions. The Production Team could release it every year at the JWC, and just put the year number on front of it (ex:. Joomla!16 CMS, Joomla!17 CMS, etc…).

The community could even get more involved, by choosing what extensions (from JED) would be included in the next release. Maybe a new article management extension could be included in one year, or even a different Template according to the distro.

SmarterQueue - The smartest way to do social media.

SmarterQueue - The smartest way to do social media.

LRTT - Limited Resource Teacher Training

LRTT - Limited Resource Teacher Training

shareOptic - Cyber security monitoring solution

shareOptic - Cyber security monitoring solution

RAD Php Blockz web framework

RAD Php Blockz web framework