Keeping MODX Relevant — Part Three
--
Persistence and Progress
My vision for MODX 3 is disruptive on purpose. And originally, this final part of my series on the ideas I have to keep MODX relevant as web technology continuously evolves was going to focus on some revolutionary concepts around persistence. But as time has marched on, I feel the time is not right for my next generation persistence library yet, nor is the code where I expected it to be by now after various self-imposed reviews of what I am doing. So instead of focusing on next generation persistence, I want to focus on changes to the existing xPDO project that will help keep MODX relevant in the coming years, as well as provide an update on where MODX 3 stands in its lifecycle.
xPDO Meets Composer
While it may not be revolutionary, the next generation of xPDO itself is available now on Packagist. You can include this in any composer-based project with the simple command:
composer require xpdo/xpdo ^3.0@dev
And while it’s not that different from previous releases of xPDO, there are some fundamental differences that will change the way you work with both xPDO and MODX.
Composer, Namespaces and Autoloading
One feature which has prevented MODX from keeping pace with many other modern PHP frameworks and content management solutions is the proprietary class loading that it depends on and inherits from xPDO 2.x. xPDO was conceived before PSR-0 was established and until now has not been able to implement support for autoloading it’s classes via these now well-established standards. xPDO 3 to the rescue.
By using namespaces and autoloading standards, xPDO can now be used as a library by any project more easily than it has traditionally. And the reduced overhead of using built-in composer-controlled autoloading is an obvious benefit of this change. No more worrying about if a parent class has already been loaded. No more preloading a bunch of base classes manually. That is the most important and fundamental change to xPDO 3 and it is what will enable future innovation on MODX 3.
We Don’t Need No Stinkin’ Maps
Another significant difference in xPDO 3 is the absence of map files. The data maintained in these files defined the mapping between fields in the database and the properties of the objects. To achieve efficient auto-loading with xPDO 3, these maps are no longer stored in separate files. Instead, they are now stored as a static member of the “platform” class. A typical generated platform class then looks like the following:
<?php
namespace xPDO\Test\Sample\mysql;
use xPDO\xPDO;
class xPDOSample extends \xPDO\Test\Sample\xPDOSample
{
public static $metaMap = array (
'package' => 'xPDO\Test\Sample',
'version' => '3.0',
'table' => 'xpdosample',
'extends' => 'xPDO\Om\xPDOSimpleObject',
'fields' =>
array (
'parent' => 0,
'unique_varchar' => NULL,
'varchar' => NULL,
'text' => NULL,
'timestamp' => 'CURRENT_TIMESTAMP',
'unix_timestamp' => 0,
'date_time' => NULL,
'date' => NULL,
'enum' => NULL,
'password' => NULL,
'integer' => NULL,
'float' => 1.0123,
'boolean' => NULL,
),
'fieldMeta' =>
array (
'parent' =>
array (
'dbtype' => 'int',
'precision' => '11',
'phptype' => 'integer',
'null' => false,
'default' => 0,
),
'unique_varchar' =>
array (
'dbtype' => 'varchar',
'precision' => '255',
'phptype' => 'string',
'null' => false,
'index' => 'unique',
),
'varchar' =>
array (
'dbtype' => 'varchar',
'precision' => '100',
'phptype' => 'string',
'null' => false,
),
'text' =>
array (
'dbtype' => 'text',
'phptype' => 'string',
'null' => true,
),
'timestamp' =>
array (
'dbtype' => 'timestamp',
'phptype' => 'timestamp',
'null' => false,
'default' => 'CURRENT_TIMESTAMP',
'attributes' => 'ON UPDATE CURRENT_TIMESTAMP',
),
'unix_timestamp' =>
array (
'dbtype' => 'int',
'precision' => '11',
'phptype' => 'integer',
'null' => false,
'default' => 0,
),
'date_time' =>
array (
'dbtype' => 'datetime',
'phptype' => 'datetime',
'null' => true,
),
'date' =>
array (
'dbtype' => 'date',
'phptype' => 'date',
'null' => true,
),
'enum' =>
array (
'dbtype' => 'enum',
'precision' => '\'\',\'T\',\'F\'',
'phptype' => 'string',
'null' => false,
),
'password' =>
array (
'dbtype' => 'varchar',
'precision' => '255',
'phptype' => 'string',
'null' => false,
),
'integer' =>
array (
'dbtype' => 'int',
'precision' => '11',
'phptype' => 'integer',
'null' => false,
),
'float' =>
array (
'dbtype' => 'decimal',
'precision' => '10,5',
'phptype' => 'float',
'null' => false,
'default' => 1.0123,
),
'boolean' =>
array (
'dbtype' => 'tinyint',
'precision' => '1',
'phptype' => 'boolean',
'null' => false,
),
),
'indexes' =>
array (
'unique_varchar' =>
array (
'alias' => 'unique_varchar',
'primary' => false,
'unique' => true,
'type' => 'BTREE',
'columns' =>
array (
'unique_varchar' =>
array (
'collation' => 'A',
'null' => false,
),
),
),
),
);
}
Not all that much different than what you are used to beyond the addition of PHP namespaces. The map just becomes part of the class now.
New CLI Tool
Part of xPDO 3 is a new CLI tool which handles reverse and forward-engineering of schemas and models. The scripts are easy to use and provide more flexible options than the techniques in 2.x afforded.
Example usage:
bin/xpdo parse-schema [[ — compile|-c]| — update=[0–2]| — regen=[0–2]] PLATFORM SCHEMA_FILE PATH
bin/xpdo write-schema [?] PLATFORM SCHEMA_FILE PATH
For instance, you can update class files now and maintain any custom code in them with the update option of the parse-schema command. This was not possible in the older xPDO code generator, but with the use of reflection, the parse-schema process in 3.x is smart enough to only update the parts of the classes it needs to.
These scripts are made available to your projects which include xPDO 3 as they make use of Composer’s vendor-binaries functionality. This basically provides symlinks from your local project’s bin directory to the bin directory that is part of the xPDO dependency.
Backwards Compatibility
Though not yet solved, backward compatibility should be achievable by providing some extended core classes in the global namespace. This should allow existing 2.x model code that is not aware of namespaces to continue operating on the 3.x runtime, and pave the way for a decent level of BC to be maintained for the models developers have created in their MODX Extras built for existing releases.
There are already unit tests dedicated to testing slightly modified legacy model definitions and these will be expanded to test unmodified ones once the namespace compatibility is accomplished.
Early Proof of Concept
Since we can all rest easy now, knowing that persistence in MODX 3 will remain familiar to what we already have, it’s time to focus on the actual implementation of existing MODX features on the new architecture. A very simple proof of concept I worked on a couple of weeks ago might provide some insight into what the foundation of MODX 3 might start to look like and be capable of. This is using Slim’s latest stable releases, not the 3.x branch with PSR-7, but the concept of how Slim’s routing, requests, and responses might replace the proprietary ones built into MODX currently is exemplified none-the-less.
https://gist.github.com/opengeek/1ed163084ba7298f64fd
For what it is worth, running a basic resource via Slim this way without the resource caching MODX wraps around it is just as fast as a cached response from the native MODX stack. That is a good indication that the overhead we can shave off by utilizing Slim has real potential.
Slim 3 Beta
I’ve also been busy working with a group of amazing contributors to get Slim 3 ready for the first beta release. It shouldn’t be too long before we see it. We are essentially just waiting for a release of the fast-route dependency that contains a new feature we needed added to the project in order to reach beta state. The feature, optional route segment support, is integrated and working, but is not yet in a release of FastRoute with at least beta stability which prevents the use of Slim 3 in any project that does not set it’s root minimum-stability to “dev”.
Once we do get Slim 3 beta into the wild, work will begin progressing at a much faster pace on MODX 3. I for one am ready to see a reinvigorated MODX CMS ecosystem that this help realize. I am hopeful this direction is one everyone can get excited about as it makes contributing much easier, productive and fun. I truly believe that through these efforts and others to increase open governance of the project, we can make MODX more accessible to all the stakeholders involved in content management for the modern web and expand adoption out of the current MODX niche.