In Joomla 3 we would create a router as a
router.php
file in the root of our component's
frontend, e.g. components/com_example/router.php
.
That file had two ways to implement a router:
-
Two separate functions whose names consisted of the name of the component without the
com_
prefix and the suffixesBuildRoute
andParseRoute
, e.g.exampleBuildRoute
andexampleParseRoute
. This was the very old way which was deprecated since Joomla 3.3 released in 2014. -
As a class extending
JComponentRouterBase
(renamed toJoomla\CMS\Component\Router\RouterBase
in later Joomla versions) or, more usually,JComponentRouterView
(introduced in Joomla 3.5 and renamed toJoomla\CMS\Component\Router\RouterView
in later Joomla versions).
If you are using the former method you have a lot of work ahead of you to convert it to a Joomla 4 compatible router. If you are using the latter method you are virtually ready, with minimal changes!
In Joomla 4 the router is implemented as the class
Service\Router
in the frontend part of our component. So,
with a component com_example
that has a namespace prefix
Acme\Component\Example
that would be the class
Acme\Component\Example\Site\Service\Router
in the
file components/com_example/src/Service/Router.php
.
That class needs to extend from
Joomla\CMS\Component\Router\RouterBase
or, more
typically Joomla\CMS\Component\Router\RouterView
,
just like in Joomla 3.5[2] and later versions.
There is one more difference in Joomla 4 and later versions. By default, the component does not know that it needs to use a router.
To understand what and why we need to do, let's go backwards.
Joomla only knows it needs to use a router factory when the component's
extension class implements the
\Joomla\CMS\Component\Router\RouterServiceInterface
.
When this is the case, Joomla knows that it can ask the extension class
to return a Router Factory object using the
createRouter
method defined in said interface.
The component's extension class does not know how to find the router
factory object; it is injected into it by the component service provider
(services/provider.php
). In its turn, it asks the
component's DI Container for that Router Factory object. The DI
Container will only know how to get a Router Factory object if we
register a Router Factory service provider in the service provider
(services/provider.php
).
Unraveling these chained dependencies we see that we need to make changes in just two files.
Your component's extension class must implement the
\Joomla\CMS\Component\Router\RouterServiceInterface
interface. The easiest way to provide its implementation is having it
use the
\Joomla\CMS\Component\Router\RouterServiceTrait
trait.
That trait requires your component service provider (e.g.
administrator/components/com_example/services/provider.php
)
to do two things. First, it needs to register a Router Factory service
provider before trying to create the component object:
$container->registerServiceProvider( new \Joomla\CMS\Extension\Service\Provider\RouterFactory ( '\\Acme\\Component\\Example' ) );
The
\Joomla\CMS\Extension\Service\Provider\RouterFactory
class is the default Joomla implementation of a component router
factory. It needs exactly one configuration parameter in its
constructor, the namespace of your component
without the Site
or
Administrator
suffix.
Then, after having created our component extension class' object, we need to inject the Router Factory object into it:
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new ExampleComponent(
$container->get(ComponentDispatcherFactoryInterface::class)
);
// ... other initialisation goes here ...
// Inject the router factory object
$component->setRouterFactory(
$container->get(
\Joomla\CMS\Component\Router\RouterFactoryInterface::class
)
);
}
);
While it looks a bit verbose, it accomplishes two things. First, it's not possible to be surprised by Joomla magically implementing a feature in your component you did not expect. Second, in the case of a router, it allows us to push dependencies (services) into our router object.
[2] The entire concept of routing using the RouterView has not changed since Joomla 3.5 which was released in 2016. You see, at this point in time development of Joomla 4 had already started and Joomla introduced the new routing to help developers migrate their extensions to the new router before Joomla 4 is released.