Work In Progress

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

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
]);