As we said when comparing the
Joomla 3 to the Joomla 4 MVC, the Dispatcher takes the place of the
front controller (controller.php
) in the legacy
Joomla 3 MVC. In some ways it also takes the place of the entry point file
(e.g. example.php
for a component named
com_example
) as it's the first code which is executed when
our component is loaded with the explicit intent of rendering
output.
Most components do not need a custom Dispatcher. The default Dispatcher provided by Joomla is just fine.
If you do decide to create a custom Dispatcher its class name
MUST be
\
(backend),
My
\Component\ComponentName
\Administrator\Dispatcher\Dispatcher\
(frontend) or
My
\Component\ComponentName
\Site\Dispatcher\Dispatcher\
(API application) where
My
\Component\ComponentName
\Api\Dispatcher\Dispatcher\
is the namespace prefix for your component, for instance
My
\Component\ComponentName
\Acme\Component\Example
. This custom Dispatcher
class must extend from
\Joomla\CMS\Dispatcher\ComponentDispatcher
.
Typically, there are two methods you might need to customise. One is
loadLanguage
which loads your component's language files. You
may have to customise that if, for example, you need to load the backend
files in the frontend or vice versa, or if you need to load some core
component's language files on top of yours.
The other method may be the dispatch()
method which
figures out the view, task and controller from the input and executes the
component.
Usually, I override the dispatch()
method to add a
minimum PHP version check and fix up the request variables so I always
have a view and task. The latter helps when writing Routers for components
which have record add / edit views in the frontend.
Such a Dispatcher would look like the following code example.
<?php namespace Acme\Component\Example\Site\Dispatcher; defined('_JEXEC') or die; class Dispatcher extends \Joomla\CMS\Dispatcher\ComponentDispatcher { /** * The default controller (and view), if none is specified in the request. * * @var string */ protected $defaultController = 'items'; /** @inheritdoc */ public function dispatch() { $minPHPVersion = '7.4.0'; if (version_compare(PHP_VERSION, $minPHPVersion, 'lt')) { throw new \RuntimeException( sprintf( 'This component requires PHP %s or later.', $minPHPVersion ) ); } $this->applyViewAndController(); parent::dispatch(); } /** * Applies the view and controller to the input object communicated to the MVC objects. * * If we have a controller without view or just a task=controllerName.taskName we populate the view to make things * easier and more consistent for us to handle. * * @return void */ protected function applyViewAndController(): void { $controller = $this->input->getCmd('controller', null); $view = $this->input->getCmd('view', null); $task = $this->input->getCmd('task', 'default'); if (strpos($task, '.') !== false) { // Explode the controller.task command. [$controller, $task] = explode('.', $task); $view = null; } if (empty($controller) && empty($view)) { $controller = $this->defaultController; $view = $this->defaultController; } elseif (empty($controller) && !empty($view)) { $controller = $view; } elseif (!empty($controller) && empty($view)) { $view = $controller; } $controller = strtolower($controller); $view = strtolower($view); $this->input->set('view', $view); $this->input->set('controller', $controller); $this->input->set('task', $task); } }