Work In Progress

This book is currently work in progress. Some sections are not yet written. Thank you for your understanding!

Joomla 3 MVC vs Joomla 4 MVC

As we already said, the basic functionality of Joomla's MVC has remained the same throughout Joomla 3 and 4. If you know how to make a Joomla 3 component you know most of what you need to make a Joomla 4 component. The differences are a few minor, but salient, points.

Namespaces. All native Joomla 4 components use PHP namespaces for their PHP code. This is a simple change in naming classes for models, views and controllers. For example, instead of your frontend model being called ExampleModelItem it will now be the class ItemModel in the namespace \Acme\Component\Example\Site\Model. The first part of the namespace in this example, \Acme\Component\Example, is the same for the whole component. This component namespace prefix consists of 3 parts:

\My\Component\ComponentName

for instance (as often used throughout this book):

\Acme\Component\Example

The 3 parts of a component namespace prefix:

  • \My vendor namespace prefix: a valid PHP namespace, unique for you, your company or your project. A valid vendor namespace prefix can for instance be \Acme. A vendor namespace prefix can also have sub-namespaces, for instance: \Acme\Support\Tools. You are free to choose your own vendor namespace, however:

    • The vendor namespace should not start with \Joomla, because component namespaces starting withIn \Joomla are reserved for core components.

    • The vendor namespace should not contain a sub-namespace starting with \Component. It is a reserved sub-namespace, that should only be used immediately AFTER the vendor namespace prefix in a component namespace.

  • \Component sub-namespace: literally "\Component", with a capital C. You should use the \Component sub-namespace in the component namespace only once: AFTER the vendor namespace and BEFORE the sub-namespace with the component name.

  • \ComponentName sub-namespace: a valid component name for Joomla as is used in com_componentname. In the namespace-part you can use camel case; in com_componentname only lowercase is used. A valid component name would for instance be Example in the namespace Acme\Component\Example for component com_example.

Namespaces are originally meant to avoid name collisions for classes, functions and constants, while conveniently using shorter names to identify those classes, functions and constants. In Joomla 3 many frontend and backend classes had the same name, like for instance ContentModelArticle, and those frontend and backend classes couldn't be used together. Namespaces to the rescue: the frontend class, including its namespace, is now called \Joomla\Component\Content\Site\Model\ArticleModel and the backend class \Joomla\Component\Content\Administrator\Model\ArticleModel.

In the PHP-world there is a standard for autoloading, which uses namespaces: PSR4. A namespace prefix is mapped to a path in the filesystem. Any sub-namespaces that are under the mapped namespace are one-on-one mapped to subdirectories with the same names. For instance the namespace \Joomla\Component\Content\Administrator is mapped to /administrator/components/com_content/src. The class \Joomla\Component\Content\Administrator\Model\ArticleModel is then found in the subdirectory /Model of /administrator/components/com_content/src. Any code with a namespace that adheres to PSR4 can automatically be autoloaded. In Joomla the mapping is cached in the administrator/cache/autoload_psr4.php file.

Because of the PSR4 autoloading, the namespace of your custom component can be used to locate any file in your component from elsewhere in Joomla. For example, to find the code files for custom form fields you may need in your component. The way to tell Joomla which namespace to use for custom form fields is with the addfieldprefix attribute in an XML form. This attribute of a fieldset (and method of Joomla\CMS\Form\FormHelper) is new since Joomla 3.8 and can be used to add a namespace for your custom fields, so they can be found with PSR4 autoloading, instead of directly providing a path as was done with the addfieldpath attribute.

Service provider. All Joomla components are passed a Dependency Injection Container (DIC) which is, in fact, a Service Locator. This even applies to components written with the Joomla 3 MVC as we'll see in the lifetime of a component. You can register services specific to your component in your service locator. At the very least, Joomla expects you to set up the extension class of your component. Unfortunately, even simple components need to have a service provider as there is no convention-over-configuration in Joomla 4's component DIC.

Extension class. The extension class replaces the entry point file (e.g. administrator/components/com_example/example.php) you had in Joomla 3 MVC. All components written with the Joomla 4 MVC have an extension class which extends from Joomla\CMS\Extension\MVCComponent. It is used to register special services used when working with your component such as the MVCFactory service (responsible for creating model, view and controller object instances), an HTML helper service which extends Joomla's HTMLHelper, a Router service for frontend search engine friendly (SEF) URL routing, and a Category service if your component uses core Categories. It also returns your component's Dispatcher which is where the execution of your component starts. For very simple components you can even use the core MVCComponent class as your extension class, without sub-classing. See, for example, what the core com_actionlogs component does.

Dispatcher instead of a front controller. In the Joomla 3 MVC paradigm you had a controller.php file in the root of your component's directory structure. This was a front-controller, supposed to figure out which controller to use to handle the specified view and task in the request. This was a bit gimmicky and error-prone, especially if you had components capable of displaying more than one discrete types of information, e.g. a downloads repository would be able to display categories, releases in a category and files in a release which made for three discrete content types which had to be handled by the same front controller. The new Dispatcher does the same job, it works without sub-classing it for most simple extensions and benefits greatly the more complex extensions which need more involved request processing.

HTML helper is a service. If you had ever registered an HTMLHelper class with static calls this is no longer the recommended method. If you need an HTML helper for your extension you need to register it through the extension class and its methods are no longer static. Since it's a real object instantiated by the extension object it has access to the component's DIC, therefore to any service you registered in your service provider or you were given by Joomla in the DIC. This makes helpers testable and means that they can access custom services (e.g. a shipping cost calculation service if you are writing an e-commerce component) without trying to contort your code.

New format for Router. Joomla 4 comes with a new Router which is instantiated through a service. The new component router superclass allows you to write efficient routers without a lot of boilerplate, duplicated and convoluted code.