This content may be out-of-date

This book was written circa 2022, when Joomla 4 was still a new thing. It has not been updated for Joomla 5 and beyond, and it's no longer being worked on. You can usually find more up-to-date information in the official Joomla! Manual.

The Category service

Categories are great and all, but if you need to get their parameters or create SEF routes for nested categories you need to somehow get information on categories. This is what the category service does for us.

It is customary — or at least I have not found a concrete reason to not be able to do otherwise — that the Category Service is created in the frontend part of your site.

Assuming our com_example component with the namespace prefix Acme\Component\Example, you need to create the class Acme\Component\Example\Site\Service\Category in the file components/com_example/src/Service/Category.php like this:

<?php
namespace Acme\Component\Example\Site\Service;

defined('_JEXEC') or die;

use Joomla\CMS\Categories\Categories;

class Category extends Categories
{
  public function __construct($options)
  {
    $options = array_merge($options, [
      'extension'  => 'com_example',
      'table'      => '#__example_items',
      'field'      => 'catid',
      'key'        => 'id',
      'statefield' => 'state',
      ]);

    parent::__construct($options);
  }

}

The array in the __construct method is all you need to customise and it's fairly self-explanatory.

extension

The name of your component e.g. com_example.

table

The name of the table holding the category items. As customary in Joomla you use #__ to denote the common table name prefix.

field

The name of the database column which contains the numeric category ID. The default is catid.

key

The name of the database column which contains the item's primary key. The default is id.

statefield

The name of the database column which contains the item's publish state. The default is state.

Now you see why I told you to use the database table field names customarily used by Joomla; they minimise the code you need to write down to two array keys: extension and table.

Unlike other services provided by your component, the category service is instantiated directly:

$catService = new Acme\Component\Example\Site\Service\Category([]);

The array in the constructor arguments is not just for show. It can help you narrow down the list of categories to be returned with the following keys:

access

Boolean. When true, Joomla will only return the categories visible to the current user. It does that by only getting from the database the categories whole access field is one of the Joomla viewing access levels the current user has access to.

published

Integer 0 or 1. When it's 1 it will only return categories which are published. When 0 it will return published, unpublished and trashed categories.

countItems

Integer 0 or 1. Note the weird capitalisation in the middle of this key's name! When it's 1, Joomla will return the number of items contained in each category at the expense of performance. Use this sparingly and only when you absolutely need it e.g. when displaying paginated views.

Also keep in mind that Joomla tries to be smart. A bit too smart, maybe. When you are on a multilingual site it will only return categories whose language is either the currently selected language or “All” (denoted by a * in the language column of the #__categories table). If you want to override this behaviour you will need to change your Categories Service constructor like so:

public function __construct($options)
{
  $options = array_merge($options, [
    'extension'  => 'com_example',
    'table'      => '#__example_items',
    'field'      => 'catid',
    'key'        => 'id',
    'statefield' => 'state',
  ]);

  parent::__construct($options);

  $this->_options['currentlang'] = $options['currentlang'] ?? $this->_options['currentlang'];
}

If you want the instance of the Categories Service to return all categories regardless of the current language in a multilingual site you can now do:

$catService = new Acme\Component\Example\Site\Service\Category([
  'currentlang' => 0
]);