Object Names and IdHandler Service Contract

Functionality overview

Categories are organized in separate category trees.
When a package admin clicks on an Administer Categories link, they are presented with a page that shows the following items: Creating a new tree involves entering tree name and description. The name must be unique among all the trees.
Upon creation of a tree, the admin is granted the 'category_read' and 'category_write' permissions.
Normally, the category_write permission should not be shared with anybody else, in the rare cases when granting this permission to another party is needed, site-wide admin intervention will be required.

In addition to mapping an entire tree to an object, admins have the option of mapping only a subtree of an existing tree. To do that, they have to click on a "Map subtree" link, after which they will see a list of tree nodes.
The mapped subtree will consist of all subcategories of the category the user selected - the category itself will not be included. Note that the mapped subtree will not be a new tree. Therefore, this option should be used only if an admin plans to use the subtree as-is and has no intention of making changes to it.

An alternative solution is available for admins who want to create a tree by copying one of the existing trees and subsequently playing around with it (moving/adding/deleting categories). To accomplish that, they would have to create a new tree, go to the admin page for this tree and click on a "Copy existing tree" link. They will see a list of available trees to copy. Clicking on the "Copy this one" link will result in creating copies of the categories from the source trees and placing them in the new tree.
This operation can be performed several times, each time the copied categories will be placed as toplevel categories of the tree.

As far as unmapping is concerned, this operation doesn't delete the mapping between categories and objects.


The creator of the category tree is granted the category_tree_read, category_tree_write and category_tree_grant_permissions privileges.

The operations one can perform on categories are:

ad (d) You cannot delete a category that has children. Also, you cannot delete a category that has objects mapped to it (do we want it or not?)
ad (e) The effect of phasing out a category is that users no longer will be able to associate objects with it, but existing associations will still be visible
Deletions and phasing it/out can be performed as bulk operations.
ad (f) sort key is used to order children of the same parent category, that is the elements of the tree are sorted first by parent, then by the sort key.


This table actually stores the information whether the tree is side-wide or not.

create table category_trees (
       tree_id                  integer primary key
                                constraint cat_trees_tree_id_fk
                                references acs_objects on delete cascade,
       site_wide_p              char(1) default 't'
                                constraint cat_trees_site_wide_p_ck
                                check (site_wide_p in ('t','f'))

Here the tree's name and description is stored in different translations.

create table category_tree_translations (
       tree_id                  integer
                                constraint cat_tree_trans_tree_id_fk
                                references category_trees on delete cascade,
       locale                   varchar2(5) not null
                                constraint cat_tree_trans_locale_fk
                                references ad_locales,
       name                     varchar2(50) not null,
       description              varchar2(1000),
       primary key (tree_id, locale)

This table stores the tree hierarchy by holding the information about the parent category. The tree is ordered by a nested index (left_ind, right_ind). Sorting is thus accomplished by means of a nested set. You can read a description of how nested sets work. This also describes how to write queries that sort correctly when using categories.

create table categories (
       category_id                  integer primary key
                                    constraint cat_category_id_fk
                                    references acs_objects on delete cascade,
       tree_id                      integer
                                    constraint cat_tree_id_fk
                                    references category_trees on delete cascade,
       parent_id                    integer
                                    constraint cat_parent_id_fk
                                    references categories,
       deprecated_p                 char(1) default 'f'
                                    constraint cat_deprecated_p_ck
                                    check (deprecated_p in ('t','f')),
       left_ind                     integer,
       right_ind                    integer

Here the actual categories are stored together with different translations.

create table category_translations (
       category_id          integer
                            constraint cat_trans_category_id_fk
                            references categories on delete cascade,
       locale               varchar2(5) not null
                            constraint cat_trans_locale_fk
                            references ad_locales,
       name                 varchar2(200),
       description          varchar2(4000),
       primary key (category_id, locale)

This table contains mapping between categories and objects

create table category_object_map (
       category_id                   integer
                                     constraint cat_object_map_category_id_fk
                                     references categories on delete cascade,
       object_id                     integer
                                     constraint cat_object_map_object_id_fk
                                     references acs_objects on delete cascade,
       primary key (object_id, category_id)
) organization index;

This is the table for the relation of trees and objects. subtree_category_id comes to play in situations when you map a subtree of an existing tree to an object.

create table category_tree_map (
        tree_id                 integer
                                constraint cat_tree_map_tree_id_fk
                                references category_trees on delete cascade,
        object_id               integer
                                constraint cat_tree_map_object_id_fk
                                references acs_objects on delete cascade,
        subtree_category_id     integer default null
                                constraint cat_tree_map_subtree_id_fk
                                references categories,
        primary key (object_id, tree_id)
) organization index;

Known Limitations

Integration with other packages

Here are the changes needed to be made to integrate with other packages.

Provide an admin-link to /categories/cadmin/one-object?object_id=@package_id@ to let admins map trees to the package instance.

Use this in ad_form to display all mapped category trees and selected categories (if editing an object):

    {category_ids:integer(category),multiple,optional {label "Categories"}
       {html {size 4}} {value {$object_id $package_id}}}
Alternatively, you can include the following in your adp:
  <include src="/packages/categories/www/include/widget" object_id=@object_id@ package_id=@package_id@>
In the processing part of ad_form use:
category::map_object -remove_old -object_id $object_id $category_ids