Work In Progress

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

Extension class

As we saw earlier in the lifetime of a component, the Extension class of a component is sort of a service locator for our component. Joomla checks if that objects implements a PHP Interface it knows about and uses the service communicated via the Interface implementation (typically one of the corresponding PHP Traits provided by Joomla) to do something useful, e.g. register an HTMLHelper helper, integrate with Tags, create SEF URLs by using a Router and so on and so forth.

If your component does not make use of any of these features you do not need to create a custom extension class for your component. Joomla gives you the perfectly serviceable Joomla\CMS\Extension\MVCComponent class which implements a minimal Joomla 4 component: it can run because it returns a Dispatcher and it can create MVC objects using the Joomla 4 MVC because it returns an MVCFactory object. This is enough for a component which only runs in the backend or runs in both the frontend and the backend but has no way of letting Joomla create SEF URLs for it. You may think this is useless but I'd contest you're not thinking simple enough. Case in point, some core Joomla components doing exactly that. For example the com_actionlogs component which only has a backend user interface.

That said, there wouldn't be much to write if all or even most components didn't need a custom extension class. You see, most components need one or more of the following features. I am documenting the features I discovered that need customisations in the extension class and give you an overview of the required changes in your component's code to make them work.

  • Use a custom HTML Helper.

    Your extension class must implement the Joomla\CMS\HTML\HTMLRegistryAwareInterface and use the Joomla\CMS\HTML\HTMLRegistryAwareTrait. The extension class must override the boot method and have a line similar to $this->getRegistry()->register('something', new MyHTMLHelper()). We'll see what that means in the section covering the HTML helper.

  • Use core categories.

    Your extension class must implement the Joomla\CMS\Categories\CategoryServiceInterface and use the Joomla\CMS\Categories\CategoryServiceTrait. Your service provider (provider.php) needs to register a Joomla\CMS\Extension\Service\Provider\CategoryFactory service provider and use the extension object's setCategoryFactory method to pass this factory to the extension object. The extension class must override the getTableNameForSection and getStateColumnForSection methods defined in the aforementioned trait and interface.

  • Integrate with Joomla's Tags feature.

    Your extension class must implement the Joomla\CMS\Tag\TagServiceInterface and use the Joomla\CMS\Tag\TagServiceTrait. The extension class must override the getTableNameForSection and getStateColumnForSection methods defined in the aforementioned trait and interface.

  • Integrate with Joomla's Custom Fields feature.

    Your extension class must implement the Joomla\CMS\Fields\FieldsServiceInterface. The extension class must implement the validateSection and getContext methods defined in the aforementioned interface.

  • Provide a Router for meaningful, human-readable SEF URLs in the frontend.

    Your component must have a class implementing the Joomla\CMS\Component\Router\RouterFactoryInterface (Router factory) and a class implementing the Joomla\DI\ServiceProviderInterface (Router factory provider). Your extension class must implement the Joomla\CMS\Component\Router\RouterServiceInterface and use the Joomla\CMS\Component\Router\RouterServiceTrait. Your service provider (provider.php) needs to register your Router factory provider and use the extension object's setRouterFactory method to pass the resulting Router factory to the extension object.

  • Let Joomla associate items between languages on multi-language sites.

    Your component must have a class extending the Joomla\CMS\Association\AssociationExtensionHelper. Your service provider (provider.php) must register this class with the Joomla\CMS\Association\AssociationExtensionInterface::class key and use the extension object's setAssociationExtension method to assign the object resulting from that service to the extension object. Your extension object needs to implement the Joomla\CMS\Association\AssociationServiceInterface and use the Joomla\CMS\Association\AssociationServiceTrait.

  • Integrate with Joomla's Workflows feature.

    Your extension class must implement the Joomla\CMS\Workflow\WorkflowServiceInterface and use the Joomla\CMS\Workflow\WorkflowServiceTrait. The extension class must override the getModelName, filterTransitions, getWorkflowTableBySection, getWorkflowContexts and getCategoryWorkflowContext methods defined in the aforementioned trait and interface.

As you can see, trying to do pretty much anything useful does require a custom extension class.

Naming your extension class

There are no hard rules for naming your component's extension class. That said, to help anyone reading your code — including yourself six or so months later — retain a modicum of their sanity it is advisable to use the convention \My\Component\ComponentName\Administrator\Extension\ComponentName+Component where:

  • \My\Component\ComponentName is the namespace prefix of your component, for instance \Acme\Component\Example

  • ComponentName is the name of your component without the com_ prefix, with the first letter in uppercase, for instance Example for component com_example

  • Component is the literal "Component". With ComponentName+Component we mean a concatenation of the component name and the literal string "Component", for instance ExampleComponent for component com_example

For example, if you have a component named com_example with the namespace prefix \Acme\Component\Example your extension class should be \Acme\Component\Example\Administrator\Extension\ExampleComponent and placed in the file administrator/components/com_example/src/Extension/ExampleComponent.php.