Transforming MODX: Tales of OO, MVC, and O/RM

Transforming MODX: Tales of OO, MVC, and O/RM

By Jason Coward  |  Updated: April 4, 2019  |  9 min read
Transforming MODX: Tales of OO, MVC, and O/RM

For 10 years, I've worked as a database administrator and web application developer. During that time I've used many different platforms, explored countless methodologies for project management/change management/etc., and have been inundated with countless opinions as to the best practices for pretty much any design or development task. Most recently, working on J2EE projects with developers that practiced Agile methodologies and that fully embraced object-oriented (OO) design techniques, I was exposed to the world of design patterns. And it may have been the most profound discovery in my development as, excuse the redundancy, a developer.

All of these experiences combined have taught me what works and what doesn't when scalability, reliability, rapid development, and long-term maintainability are important. With that in mind, I wanted to share why and how my experience with design patterns in particular, are guiding me through the transformation of the MODX core framework. In short, the end game is to be able to do all the things you've come to love and expect with MODX, but in a completely different way behind the scenes. MODX then becomes a more robust, scalable, capable, maintainable, and yes, even more flexible platform, with minimal impact on existing users.

THE TRANSFORMATION

Over a year ago, I had the idea of recreating MODX as an OO framework. I explored the various PHP frameworks to see if any could help fast-track an implementation.

My attention was first captured by Propel1, which can help generate fairly complex OO data models from relational data structures. I soon found out though, that porting a project designed originally for Java was not the right approach for the performance goals I had in mind. Many PHP servers are not on enterprise-level hardware needed for acceptable user experiences with complex enterprise-driven design patterns, not to mention the countless shared servers in existence. The work done in creating this Propel-prototype of an OO MODX though helped refine my vision.

I continued searching but quickly concluded what I sought didn't exist. At that point I began to design and construct the foundation of what has come to power the new MODX core: xPDO2. xPDO is my attempt at rethinking object-relational management, with the idiosyncrasies of PHP in mind.

Six months later, I deployed my first live xPDO project, a custom OO data model used inside a MODX site. Shortly thereafter, I rewrote my original Propel-prototype on top of xPDO (referred to as “the new core”). I recently deployed an actual site on the new core with exciting results: almost complete compatibility with existing MODX components, running on a totally new, OO core engine. This new core solidly lays a foundation for a future as an enterprise Content Management Framework, but maintains the user-friendliness and ease of development that people love about MODX.

Now, when reading or discussing frameworks today, especially those in PHP or Ruby, you often read or hear the term MVC3 used. The Model-View-Controller pattern is one of the most frequently discussed design patterns. But it's just a design pattern, and there can be many implementations of that pattern – some simple and some complex. This can lead to some misconceptions on what it means to be an MVC framework. So before we talk about MODX and MVC, we need to understand that this is describing only suggested approaches for designing or structuring an implementation. With that said, let's review how the new MODX core implements MVC and the many patterns it encompasses.

THE MODX MVC IMPLEMENTATION

Some of the key goals I had in mind when approaching the rewrite of MODX were:

  • To simplify the semantics of the framework

  • Reduce the various concepts to key patterns of common behavior

  • Centralize the domain logic (i.e. application or business logic)

  • Reduce code redundancy and overall footprint

  • Further improve the extensibility of every aspect of the core framework

After experimenting with several designs to meet these goals, I finally settled on one with 4 major parts, each of which represent an individual portion of, or in cases, an entire recursive variation of an MVC design.

1. CONTEXTS: FLEXIBLE FRONT CONTROLLERS

Front controllers4 are the first pattern represented in the transformed MODX, a variation of the “C” in MVC. Front-controllers are responsible for receiving requests and dispatching them to the appropriate place in the framework. Typically, there is a single front-controller that handles all requests. The index.php file in the MODX root directory is just such a front-controller. However, this implementation creates a potential bottleneck for the index.php resource itself (and thus the web server processes), and does not allow for any custom optimization of this dispatching process for specific kinds of requests (e.g. Ajax, XML-RPC, etc.).

To address this in my design, I decided to take the idea of Contexts, which is typically embedded within a front controller, and externalize it. Each Context in the new core can define it's own entry file and by doing so, we can reduce the bottleneck as needed, allow very flexible multi-domain/sub-domain capabilities (limited only by the web server environment), and allow Ajax or web service developers to optimize their own dispatchers. Essentially every Context can be served by it's own front controller, but still have access to the core model, or even share global resources. You can even serve multiple Contexts from a single front-controller, so having this unique entry-point is not a requirement to define a Context, but rather a useful option to allow Contexts to logically partition your deployment.

2. RESOURCES: MORE CONTROLLER PATTERNS

Resources represent unique physical web assets, from web pages, to symbolic links, to Ajax or XML web services – anything that can traditionally be accessed via a URL (Universal Resource Locater). Use the simple Page Controller5 implementation that aggregates some simple Elements (see part 3 below) representing Views (the “V” in MVC), or create a completely custom Application Controller6 Element that is essentially the front-end to an MVC subset embedded within the overall MVC pattern of the framework (i.e. Recursive MVC).

Resources consist of a single “base” Element, or “Template”, and any number of additional Elements that are aggregated and processed to provide the Content for the Resource to return to the requesting client. How they do that is completely up to the class (or type) of Resource being processed. The possibilities are virtually unlimited.

3. ELEMENTS: VIEWS AND EVEN MORE CONTROLLERS

“Reusable Elements of Content.” Every Element in the new design defines source content and a set of properties (or parameters), which provide output of an expected type when processed by the MODX parsing engine. They can be “Chunks” of raw text, HTML, or XML, “Snippets” of PHP, etc.

In addition, Elements can aggregate other Elements, so you can create reusable sets of related Elements that define common behavior for your site(s). This is similar to the concept of Web Flows7 in the Spring MVC framework that is gaining popularity in the J2EE world, and combined with Contexts and Resources, robust, stateful web applications in PHP will be not only possible, but even practical.

Elements can also define and/or deliver alternate content for specific Cultures. Cultures represent a set of properties that define language, date formatting, currency formatting, etc., on a more granular scale than organizing it by language only. This will provide for easy localization and/or internationalization capabilities in a variety of ways. Add this together with the ability to combine custom Elements and attach them directly to a Resource, or even as the base Element of a Resource, and it will be trivial to implement translation features that fit custom work-flow requirements, easily attach custom Elements that define robust permissions, and more.

If that wasn't enough, to round out the capabilities of Elements, revisions to each Element's source content can also be tracked (by Culture) and used for audit trails, change management, and/or rollback purposes.

4. THE CORE: A CENTRAL MODEL OF DOMAIN LOGIC

xPDO provides raw data access using native PDO8 extensions when available, falling back to a PDO emulation framework that works all the way back to PHP 4.3.x. It provides a very lightweight O/RM (object-relational mapping) layer with access performance similar to using the current MODX DB API. With native PDO performance naturally improving upon that (it's a compiled PHP extension written in C), the choice of using PDO as the exclusive database abstraction layer, turned out better than I ever imagined.

One of the key motivations for any Model (the “M” in MVC), is to encapsulate all application, or domain logic. Instead of having such behavior spread around in your scripts, and having to redundantly write the same code, the Model patterns reveal there is a better way to organize these reusable pieces of logic. The benefits are numerous and range from simple reduction in total code to exposing great new ways to add features that would be next to impossible to develop (or maintain at least) without the centralized Model.

With an appropriate manager interface, the new core will be able to provide facilities for managing custom Models within a MODX deployment. Reverse-engineer your proprietary databases, forward-engineer classes for them, or just make up some new tables and have xPDO manage the physical storage requirements for you. This means web-masters will not have to execute a SQL script to add custom data tables. The ultimate goal is to offer a visual editor for designing/managing a custom Model or even altering the core MODX model, within the MODX manager itself.

ENOUGH WITH THE PATTERNS ALREADY!

In any case, there are even more patterns used throughout the new MODX design than those discussed here, and I think it's important to share them as motivation for “fixing what ain't broke.” For instance, xPDO uses the ViewCache9 pattern to provide robust result-set caching for all data access and domain logic in your Model. Another variation of ViewCache provides for a Registry (or message queue) that can be used as custom state containers. This provides for a level of granularity in session/application state management that simply is not possible in most PHP frameworks, and it's an important feature for an Ajax-capable tool-set. But I'll discuss these, and some more juicy design topics in forthcoming articles.






References:

1 — Propel is a more mature object/relational mapping tool for PHP 5. More info at http://propel.phpdb.org/

2 — xPDO is the lightweight object/relational mapping tool for PHP 4 and 5 I've been authoring. More info at http://xpdo.org/

3 — MVC is an architectural design pattern that aggregates another set of design patterns to form a multi-tier system design that separates control logic, from presentation logic, from data access and domain logic. Learn more about MVC at http://en.wikipedia.org/wiki/Model-view-controller

5 — The Page Controller pattern is discussed at http://www.martinfowler.com/eaaCatalog/pageController.html

6 — Application Controllers are discussed at http://www.martinfowler.com/eaaCatalog/applicationController.html

7 — Spring Web Flow (SWF) is a component of the Spring Framework's web stack focused on the definition and execution of user interface (UI) flow within a web application. More info at http://www.springframework.org/webflow

8 — PDO is the standard database access layer for PHP 5.1+. More info at http://php.net/pdo