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:
-
\
vendor namespace prefix: a valid PHP namespace, unique for you, your company or your project. A valid vendor namespace prefix can for instance beMy
\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. -
\
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 beComponentName
Example
in the namespaceAcme\Component\Example
for componentcom_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.