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