Table of Contents
- The Joomla MVC: an introduction
- Joomla 3 MVC vs Joomla 4 MVC
- The lifetime of a component
- Directory structure
- Service provider
- Extension class
- Dispatcher
- Namespaces and MVC
- The MVCFactory
- Models
- Controllers
- Views
- Tables
- HTML helper service
- Categories
- Router
- Dashboard
- The installation script
- Component menus
- Passing data from the backend to the JavaScript on the page
- Language files
- Mail Templates
- The CLI application
- The API application
- Integration with Scheduled Tasks
- Custom fields
The Joomla component is arguably the most important extension type. It's not just the sheer fact that it is an application inside an application, letting us create custom experiences otherwise nearly impossible with just core code, it is also that Joomla embraces the need for this kind of custom experiences and has heavily invested in making component development relatively easy. This is in stark contrast with WordPress where your experience is far and foremost defined by its core code, custom experiences outside custom content types are actively discouraged and there is no sensible API for creating an equivalent extension type without a lot of reinventing the wheel, bending over backwards and judicious application of the Dark Arts.
Joomla came with a strong legacy of modular architecture in version 1.0, when it was a little more than a fork of and improvement upon Mambo 4, its predecessor. Joomla 1.5 introduced extension developers to the concept of MVC (Model-View-Controller) where each component has defined and logical structure, separating business logic from presentation. Joomla 4 improves upon this legacy, by further polishing the MVC and embracing concepts introduced to the PHP developer's arsenal over the last decade and a half.
Before delving into improvements and changes in Joomla 4 I think a little Joomla MVC refresher is in order. This is especially useful if you are used to the MVC definition from a college Computer Science class or have used real MVC in other programming languages or even PHP frameworks (e.g. in Laravel the typical Model is Eloquent which works completely differently, the View is your Blade files and the Controller is more of a collection of middleware rather than a single class — it's still MVC but a different dialect in the same way Spanish, Italian and French are all Romance languages).
Joomla follows the MVC model typically called “skinny controller - fat model”. This puts most of the business logic into the Model and keeps the Controller a relatively nimble affair. Further to that, Joomla also uses another class called a Table to abstract our interaction with the persistence layer objects (that's a fancy, pretentious way of saying “database table”). So, it's really an MVCT approach.
But what are these Controllers, Models and Views anyway?
The Controller consists of one or more tasks implemented as public methods. Each one of them tells the controller to do something. For example display an article, publish or unpublish an article, delete an article, log in the user, check the Multi-factor Authentication provided by the user, create a user data deletion request and so on and so forth. Controllers are orchestrators; they know what work needs to be done but they do not do it themselves. The Controller handles requests: it reads the user input and decides what needs to happen next which is invariably one of two things. For simple tasks with no output like publishing an article, deleting an article, logging in a user etc it will get the Model, tell it what to do and then issue a redirection to a different page, possibly setting a (very short!) message to show to the user. Most of the time it will need to create a document, e.g. an HTML page, a JSON document, an RSS feed etc. In this case it will get the appropriate View, push the Model to it and ask it to render itself. It then takes the rendered document and echoes it; Joomla will intercept that and decide what to do with the document effectively returned by the Controller. If an error occurred the Controller will catch it and decide what to do with it: swallow it or push it up the stack so that it ends up becoming an error page for the user.
Note that unlike the normative Controller of the MVC pattern the Joomla component's Controller DOES NOT normally push data to the Model. Yes, this is a violation of the separation of concerns. However, addressing that would be a massive backwards compatibility break which would necessitate the rethinking and rewriting of all Joomla components, core and third party. As a result we are unlikely to ever see this changing.
The Model is the workhorse of the component. It has the business logic, i.e. it knows how to get things done. In most cases it is a data-aware model which means that it knows how to get stuff from the database, put stuff back to the database and perform other auxiliary functions with the database data. It does NOT handle any presentation logic, i.e. it will NOT output any HTML. It returns raw data whenever it is asked to. Therefore you can use a Model in any context: inside the component, in a CLI script, in the API application (which only handles and returns JSON data), a Scheduled Task, a module, a plugin, even a template (though that would be a bit of an architectural violation; I won't judge you harshly if you do that because you're on a deadline and/or a shoestring budget).
Note that unlike the normative Model of the MVC pattern the Joomla component's Model will seek data from the user session and if it's not found there it will try to get it from the request. This makes it a pain in the posterior to use outside the frontend, backend and API applications, e.g. in a CLI application. Yes, there's a trick to that (and probably a section I will have to write at some point): set its state manually and it will no longer try to get data from the request.
As I said, Joomla also has a Table class which, architecturally speaking, is somewhere between a Model and a Persistence Layer. But we're not CS majors, we're Joomla extension developers. What we need to know is that the Table class is an abstraction which represents exactly one record of a database table. Table classes only exist in the backend of your component but can be used anywhere. They are used either inside a Model or directly on their own.
Tables are used by Models but not when returning multiple rows. When you run getItems on a ListModel you get an array of stdClass objects. This sounds odd at first but it makes sense; Models can join multiple tables and return embellished data in lists. For example, you may not just get a user ID but also the user's name and email address as separate fields. In most (but not all!) cases you could instantiate a Table object and call its bind() method with one of the aforementioned stdClass objects as its argument to get a Table object representation of your data. Just remember in this case that instantiating a Table object is computationally expensive as it needs to parse the database table's column definitions. Create an instance of the Table object. Then clone it for each row you are processing and bind the data to the Table object's clone. When processing a few dozen or more rows it can save you hundreds of milliseconds of page load time.
Then, we have Views. Now, this is the biggest departure of the normative MVC pattern. In Computer Science the View only renders information in a suitable way for the user to understand. A Joomla component's View is actually part controller and part ViewModel. Which means that Joomla's MVC is neither MVC nor MVVM, it's its own thing. But, as we said before, we are not CS majors, we are Joomla extension developers. So let's see what our View does.
Our View gets data from the Model. It does a bit of error checking to make sure nothing is amiss — if it is, it will show an appropriate error state be it the new in Joomla 4 Empty State (guiding the user to please create some data when we have nothing to show them) or an error page if something has gone so bad we don't know what to do. It is also responsible for setting up the page metadata (frontend) or the page's Title and Toolbar (backend) which is View-related stuff in the same way that making coffee is related to hosting an in-person meeting: not really your job but people would be really upset if nobody did it.
In the end, the View renders the information in an appropriate format for the user — which is what a View is really supposed to do if it wants to be called a View! For HTML pages it calls one or more View Template files to render some HTML. For other view types such as JSON, Raw, XML, Feed and so on a view template file may be used but it's neither necessary nor does it always make sense. If you're returning a JSON document or a CSV it makes far more sense to construct it directly in your View code and return it than going through an unnecessary round-trip through a view template file.
Finally, we need to talk about the View Template files. These are the real View of the MVC pattern: they convert the raw data we got from our Model to the HTML which will be displayed to the user. Why not have the View return the HTML directly? Well, we could but we'd have two problems. First, the View itself is also part Controller and part ViewModel therefore we'd have an issue with the separation of concerns, mixing business logic with presentation logic (bad idea; we are using MVC to avoid this bad practice). Second, Joomla's raw, unadulterated power comes from the fact that our end users can override View Templates in their sites, thereby changing the presentation of our component in ways we can neither think of nor support in any meaningful way across our entire user base.
This is the overview of Joomla's MVC and you'll be happy to know that it has not actually changed ever since Joomla 1.5. Some implementation details have changed but the core concepts — the good, the bad and the ugly parts alike — have remained unchanged in Joomla 4. In other words, if you already have a perfectly serviceable component written for Joomla 3 you can migrate it to Joomla 4. It's not a different language (like Italian to Spanish), it's a different dialect. Yes, you'll need to learn the vernacular of the new dialect but it's much, much easier than learning a new language. I am saying that as someone who had to learn three foreign (human) languages and more programming languages than I care to list.