Skip to content

Commit 3700351

Browse files
authored
Add codeblock style
1 parent 36951c8 commit 3700351

File tree

2 files changed

+303
-258
lines changed

2 files changed

+303
-258
lines changed

docs/using-core-functions/categories/implementing-categories-in-components.md

Lines changed: 157 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -11,48 +11,55 @@ All the category data is held in the Categories table; you just have specify a f
1111
## Add a field to capture the category
1212
Where you allow users to add new records or edit existing records you'll want to extend the form to capture the associated category. You can add something like what's below to the XML file for adding or editing your component records:
1313

14-
<field
15-
name="catid"
16-
type="category"
17-
extension="com_yourcomponent"
18-
class="inputbox"
19-
default=""
20-
label="JCATEGORY"
21-
required="true"
22-
>
23-
<option value="0">JOPTION_SELECT_CATEGORY</option>
24-
</field>
14+
```xml
15+
<field
16+
name="catid"
17+
type="category"
18+
extension="com_yourcomponent"
19+
class="inputbox"
20+
default=""
21+
label="JCATEGORY"
22+
required="true"
23+
>
24+
<option value="0">JOPTION_SELECT_CATEGORY</option>
25+
</field>
26+
```
2527

2628
Provided you call the `name` of the field the same as the name of your database column Joomla will map the data from the submitted form through to the database table for you.
2729

2830
## Add entries in the administrator submenu
2931
You should add an entry in your component's submenu to enable administrators to manage the category data. You can do this within the administrator `<submenu>` tags in your component manifest XML file:
3032

31-
<administration>
32-
<submenu>
33-
<menu link="option=com_categories&amp;extension=com_yourcomponent">JCATEGORIES</menu>
34-
</submenu>
33+
```xml
34+
<administration>
35+
<submenu>
36+
<menu link="option=com_categories&amp;extension=com_yourcomponent">JCATEGORIES</menu>
37+
</submenu>
38+
</administration>
39+
```
3540

3641
## Specify ACLs for the Categories
3742
You need to access some entries into your access.xml, eg
3843

39-
<?xml version="1.0" encoding="utf-8" ?>
40-
<access component="com_yourcomponent">
41-
<section name="component">
42-
<action name="core.admin" title="JACTION_ADMIN"/>
43-
<action name="core.manage" title="JACTION_MANAGE"/>
44-
<action name="core.create" title="JACTION_CREATE"/>
45-
<action name="core.delete" title="JACTION_DELETE"/>
46-
<action name="core.edit" title="JACTION_EDIT"/>
47-
<action name="core.edit.state" title="JACTION_EDITSTATE"/>
48-
</section>
49-
<section name="category">
50-
<action name="core.create" title="JACTION_CREATE"/>
51-
<action name="core.delete" title="JACTION_DELETE"/>
52-
<action name="core.edit" title="JACTION_EDIT"/>
53-
<action name="core.edit.state" title="JACTION_EDITSTATE"/>
54-
</section>
55-
</access>
44+
```xml
45+
<?xml version="1.0" encoding="utf-8" ?>
46+
<access component="com_yourcomponent">
47+
<section name="component">
48+
<action name="core.admin" title="JACTION_ADMIN"/>
49+
<action name="core.manage" title="JACTION_MANAGE"/>
50+
<action name="core.create" title="JACTION_CREATE"/>
51+
<action name="core.delete" title="JACTION_DELETE"/>
52+
<action name="core.edit" title="JACTION_EDIT"/>
53+
<action name="core.edit.state" title="JACTION_EDITSTATE"/>
54+
</section>
55+
<section name="category">
56+
<action name="core.create" title="JACTION_CREATE"/>
57+
<action name="core.delete" title="JACTION_DELETE"/>
58+
<action name="core.edit" title="JACTION_EDIT"/>
59+
<action name="core.edit.state" title="JACTION_EDITSTATE"/>
60+
</section>
61+
</access>
62+
```
5663

5764
## Category Summary by Published State
5865
On the administrator Categories form it's usual to display for each category record the number of your component records which have Published / Unpublished / Archived / Trashed state. To implement this `com_categories` boots your component and calls the `countItems()` function (defined in Joomla\CMS\Categories\CategoryServiceInterface) on your Extension class instance. You can either provide the `countItems()` function directly or (if your category field is called `catid`) use the Joomla\CMS\Categories\CategoryServiceTrait and override
@@ -79,123 +86,129 @@ The preferred way of getting access to the Categories object is by instantiating
7986

8087
The services/provider.php file below is for a component `com_example`, with namespace `Mycompany\Component\Example` (as defined in the xml manifest file). The lines relating to obtaining the CategoryFactory have been commented to explain what's going on.
8188

82-
<?php
89+
```php
90+
<?php
8391

84-
defined('_JEXEC') or die;
92+
defined('_JEXEC') or die;
8593

86-
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
87-
use Joomla\CMS\Extension\ComponentInterface;
88-
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory as ComponentDispatcherFactoryServiceProvider;
89-
use Joomla\CMS\Extension\Service\Provider\CategoryFactory as CategoryFactorServiceProvider;
90-
use Joomla\CMS\Extension\Service\Provider\MVCFactory as MVCFactoryServiceProvider;
91-
use Joomla\CMS\Extension\Service\Provider\RouterFactory as RouterFactoryServiceProvider;
92-
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
93-
use Joomla\DI\Container;
94-
use Joomla\DI\ServiceProviderInterface;
95-
use Joomla\CMS\Categories\CategoryFactoryInterface;
96-
use Joomla\CMS\Component\Router\RouterFactoryInterface;
97-
use Mycompany\Component\Example\Administrator\Extension\ExampleComponent;
98-
use Joomla\Database\DatabaseInterface;
94+
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
95+
use Joomla\CMS\Extension\ComponentInterface;
96+
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory as ComponentDispatcherFactoryServiceProvider;
97+
use Joomla\CMS\Extension\Service\Provider\CategoryFactory as CategoryFactorServiceProvider;
98+
use Joomla\CMS\Extension\Service\Provider\MVCFactory as MVCFactoryServiceProvider;
99+
use Joomla\CMS\Extension\Service\Provider\RouterFactory as RouterFactoryServiceProvider;
100+
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
101+
use Joomla\DI\Container;
102+
use Joomla\DI\ServiceProviderInterface;
103+
use Joomla\CMS\Categories\CategoryFactoryInterface;
104+
use Joomla\CMS\Component\Router\RouterFactoryInterface;
105+
use Mycompany\Component\Example\Administrator\Extension\ExampleComponent;
106+
use Joomla\Database\DatabaseInterface;
99107

100108

101-
return new class implements ServiceProviderInterface {
109+
return new class implements ServiceProviderInterface {
110+
111+
public function register(Container $container): void
112+
{
102113

103-
public function register(Container $container): void
104-
{
105-
106-
/* The line below will call register() in libraries/src/Extension/Service/Provider/CategoryFactory.php
107-
* That function will create an entry in our component's child DIC with:
108-
* key = 'Joomla\CMS\Categories\CategoryFactoryInterface'
109-
* value = a function which will
110-
* 1. create an instance of CategoryFactory, instantiated with the namespace string passed in
111-
* 2. call setDatabase() on that CategoryFactory instance, so that it's got access to the database object
112-
* 3. return the CategoryFactory instance
113-
*/
114-
$container->registerServiceProvider(new CategoryFactorServiceProvider('\\Mycompany\\Component\\Example'));
115-
$container->registerServiceProvider(new MVCFactoryServiceProvider('\\Mycompany\\Component\\Example'));
116-
$container->registerServiceProvider(new ComponentDispatcherFactoryServiceProvider('\\Mycompany\\Component\\Example'));
117-
$container->registerServiceProvider(new RouterFactoryServiceProvider('\\Mycompany\\Component\\Example'));
118-
$container->set(
119-
ComponentInterface::class,
120-
function (Container $container) {
121-
// The next line creates an instance of our com_example component Extension class
122-
$component = new ExampleComponent($container->get(ComponentDispatcherFactoryInterface::class));
123-
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
124-
/* The line below will get from the DIC the entry with key 'Joomla\CMS\Categories\CategoryFactoryInterface'
125-
* The CategoryFactory instance will be returned, and we'll save a reference to it in our component by
126-
* calling setCategoryFactory(), passing it in as the parameter
127-
*/
128-
$component->setCategoryFactory($container->get(CategoryFactoryInterface::class));
129-
$component->setRouterFactory($container->get(RouterFactoryInterface::class));
130-
$component->setDatabase($container->get(DatabaseInterface::class));
131-
132-
return $component;
133-
}
134-
);
135-
}
136-
};
114+
/* The line below will call register() in libraries/src/Extension/Service/Provider/CategoryFactory.php
115+
* That function will create an entry in our component's child DIC with:
116+
* key = 'Joomla\CMS\Categories\CategoryFactoryInterface'
117+
* value = a function which will
118+
* 1. create an instance of CategoryFactory, instantiated with the namespace string passed in
119+
* 2. call setDatabase() on that CategoryFactory instance, so that it's got access to the database object
120+
* 3. return the CategoryFactory instance
121+
*/
122+
$container->registerServiceProvider(new CategoryFactorServiceProvider('\\Mycompany\\Component\\Example'));
123+
$container->registerServiceProvider(new MVCFactoryServiceProvider('\\Mycompany\\Component\\Example'));
124+
$container->registerServiceProvider(new ComponentDispatcherFactoryServiceProvider('\\Mycompany\\Component\\Example'));
125+
$container->registerServiceProvider(new RouterFactoryServiceProvider('\\Mycompany\\Component\\Example'));
126+
$container->set(
127+
ComponentInterface::class,
128+
function (Container $container) {
129+
// The next line creates an instance of our com_example component Extension class
130+
$component = new ExampleComponent($container->get(ComponentDispatcherFactoryInterface::class));
131+
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
132+
/* The line below will get from the DIC the entry with key 'Joomla\CMS\Categories\CategoryFactoryInterface'
133+
* The CategoryFactory instance will be returned, and we'll save a reference to it in our component by
134+
* calling setCategoryFactory(), passing it in as the parameter
135+
*/
136+
$component->setCategoryFactory($container->get(CategoryFactoryInterface::class));
137+
$component->setRouterFactory($container->get(RouterFactoryInterface::class));
138+
$component->setDatabase($container->get(DatabaseInterface::class));
139+
140+
return $component;
141+
}
142+
);
143+
}
144+
};
145+
```
137146

138147
And to match this you need to have some key lines in your Extension class:
139148

140-
<?php
149+
```php
150+
<?php
141151

142-
namespace Mycompany\Component\Example\Administrator\Extension;
152+
namespace Mycompany\Component\Example\Administrator\Extension;
143153

144-
defined('JPATH_PLATFORM') or die;
154+
defined('JPATH_PLATFORM') or die;
145155

146-
use Joomla\CMS\Categories\CategoryServiceInterface;
147-
use Joomla\CMS\Categories\CategoryServiceTrait;
148-
use Joomla\CMS\Extension\BootableExtensionInterface;
149-
use Joomla\CMS\Extension\MVCComponent;
150-
use Psr\Container\ContainerInterface;
151-
use Joomla\CMS\Component\Router\RouterServiceTrait;
152-
use Joomla\CMS\Component\Router\RouterServiceInterface;
153-
use Joomla\Database\DatabaseAwareTrait;
156+
use Joomla\CMS\Categories\CategoryServiceInterface;
157+
use Joomla\CMS\Categories\CategoryServiceTrait;
158+
use Joomla\CMS\Extension\BootableExtensionInterface;
159+
use Joomla\CMS\Extension\MVCComponent;
160+
use Psr\Container\ContainerInterface;
161+
use Joomla\CMS\Component\Router\RouterServiceTrait;
162+
use Joomla\CMS\Component\Router\RouterServiceInterface;
163+
use Joomla\Database\DatabaseAwareTrait;
154164

155-
156-
class ExampleComponent extends MVCComponent implements
157-
CategoryServiceInterface, RouterServiceInterface, BootableExtensionInterface
158-
{
159-
use CategoryServiceTrait;
160-
use RouterServiceTrait;
161-
use DatabaseAwareTrait;
162-
163-
// Use a static variable to store the Categories instance
164-
public static $categories;
165165

166-
public function boot(ContainerInterface $container)
167-
{
168-
self::$categories = $this->categoryFactory->createCategory();
169-
}
170-
...
166+
class ExampleComponent extends MVCComponent implements
167+
CategoryServiceInterface, RouterServiceInterface, BootableExtensionInterface
168+
{
169+
use CategoryServiceTrait;
170+
use RouterServiceTrait;
171+
use DatabaseAwareTrait;
172+
173+
// Use a static variable to store the Categories instance
174+
public static $categories;
175+
176+
public function boot(ContainerInterface $container)
177+
{
178+
self::$categories = $this->categoryFactory->createCategory();
179+
}
180+
// ...
181+
```
171182

172183
The `CategoryServiceTrait` which is used is what contains the function `setCategoryFactory` which was used in services/provider.php to save the returned CategoryFactory. The function saves it in an instance variable `$categoryFactory`.
173184

174185
Whenever Joomla wants to execute the component it runs the services/provider.php file (which creates the Extension instance) and then calls `boot()` on this Extension object. The code in `boot()` above accesses the stored CategoryFactory and calls `createCategory()` on it to create the `Categories` instance. The result of this is stored in a static variable which can be accessed anywhere in the component using
175186

176-
$categories = ExampleComponent::$categories;
187+
`$categories = ExampleComponent::$categories;``
177188

178189
The CategoryFactory `createCategory()` code will use the namespace which was passed into it (originally in services/provider.php above) and will try to instantiate a class <namespace>\Site\Service\Category, raising an exception if it does not exist. So you need to provide a file within your site area src/Service/Category.php similar to the following:
179190

180-
<?php
191+
```php
192+
<?php
181193

182-
namespace Mycompany\Component\Example\Site\Service;
194+
namespace Mycompany\Component\Example\Site\Service;
183195

184-
use Joomla\CMS\Categories\Categories;
196+
use Joomla\CMS\Categories\Categories;
185197

186-
\defined('_JEXEC') or die;
198+
\defined('_JEXEC') or die;
187199

188-
class Category extends Categories
189-
{
200+
class Category extends Categories
201+
{
190202

191-
public function __construct($options = array())
192-
{
193-
$options['table'] = '#__example';
194-
$options['extension'] = 'com_example';
203+
public function __construct($options = array())
204+
{
205+
$options['table'] = '#__example';
206+
$options['extension'] = 'com_example';
195207

196-
parent::__construct($options);
197-
}
208+
parent::__construct($options);
198209
}
210+
}
211+
```
199212

200213
In this way the array of options for the [Categories API](https://manual.joomla.org/docs/using-core-functions/categories/using-categories-api) are defined. (You can pass these options as a parameter to the `createCategory()` call but you still have to provide your Category.php class file).
201214

@@ -213,30 +226,36 @@ There are some other changes you'll also need to implement.
213226
### Administrator submenu
214227
You'll need to have something like:
215228

216-
<menu link="option=com_categories&amp;extension=com_product.size">Size categories</menu>
217-
<menu link="option=com_categories&amp;extension=com_product.price">Price categories</menu>
229+
```xml
230+
<menu link="option=com_categories&amp;extension=com_product.size">Size categories</menu>
231+
<menu link="option=com_categories&amp;extension=com_product.price">Price categories</menu>
232+
```
218233

219234
to create the 2 categories menuitems in the administrator submenu for your component.
220235

221236
### Administrator edit item
222237
In the administrator edit product xml form (where you define each product, and its associated size and price categories) your fields for capturing the categories must distinguish between them, eg
223238

224-
<field name=catid1 type="category" extension="com_product.size" …/>
225-
<field name=catid2 type="category" extension="com_product.price" …/>
239+
```xml
240+
<field name=catid1 type="category" extension="com_product.size" …/>
241+
<field name=catid2 type="category" extension="com_product.price" …/>
242+
```
226243

227244
and similarly for any filter fields in `filter_products.xml` for filtering the list of products shown in the administrator products form.
228245

229246
### Category Summary.
230-
In your Extension class you'll need to provide the `countItems()` function which is in the trait Joomla\CMS\Categories\CategoryServiceTrait. `com_categories` will call this function passing in the category `section``, and if you're using `ContentHelper::countRelations()` to provide the summary then you'll need to set the appropiate category id field for each section – eg 'catid1' for section 'size' and 'catid2' for section 'price'. An example is below.
231-
232-
public function countItems(array $items, string $section)
233-
{
234-
$config = (object) [
235-
'related_tbl' => $this->getTableNameForSection($section),
236-
'state_col' => $this->getStateColumnForSection($section),
237-
'group_col' => $section == "size" ? 'catid1' : 'catid2',
238-
'relation_type' => 'category_or_group',
239-
];
240-
241-
ContentHelper::countRelations($items, $config);
242-
}
247+
In your Extension class you'll need to provide the `countItems()` function which is in the trait `Joomla\CMS\Categories\CategoryServiceTrait`. `com_categories` will call this function passing in the category `section`, and if you're using `ContentHelper::countRelations()` to provide the summary then you'll need to set the appropiate category id field for each section – eg 'catid1' for section 'size' and 'catid2' for section 'price'. An example is below.
248+
249+
```php
250+
public function countItems(array $items, string $section)
251+
{
252+
$config = (object) [
253+
'related_tbl' => $this->getTableNameForSection($section),
254+
'state_col' => $this->getStateColumnForSection($section),
255+
'group_col' => $section == "size" ? 'catid1' : 'catid2',
256+
'relation_type' => 'category_or_group',
257+
];
258+
259+
ContentHelper::countRelations($items, $config);
260+
}
261+
```

0 commit comments

Comments
 (0)