Dynamic Object Types and Attributes
The goal of this page is to come up with a generic specification for an OpenACS core package that allows us to create object types using a WebUI and assign attributes to it. Furthermore, using this interface it should be possible to extend any other existing object type and seamlessly have it work in the respective pages without many changes needed.
At the moment three different approaches exist to tackle (part) of this problem. This needs to be modified so we only get one version out of it. The three approaches are:
ams is used by contacts as its primary storage for attributes. It's primary focus is to easily extend existing object types with attributes.
AMS stores the additional attributes in a meta table system from which it retrieves the values again. This allows flexibility as you can reuse attributes easily and you do not have to create database statements when you want to extend and object type. Additionally you do not need one table per object type and you are not limited by the number of rows a table can have as a maximum.
Dynamic Types is used by project manager to enhance the tasks and the project attributes. It is furthermore used in custom applications by cognovís, Solution Grove and xarg Ltd.
(DAVEB) In general, Lee and I also want to support,
- Multiple storage models (generic, type-specific table)
- Defining forms for multiple objects on one "page"
- Defining forms that are not associated with an object
So I think we have the same ideas. This is where I think the form definition framework needs to be separate from the object type, so we can define a form and where the data goes, whether it is one object, multiple objects, or no object. We definitely should extend, and improve the existing acs_attributes table and features to support what we need.
Dynfields (formerly known as flexbase) is the dynamic attribute system used by ]po[ (formerly known as Project/Open) and based of AMS while trying to get the good things from dynamic types in it as well.
This package is based on the xotcl object relational mapping and adds the the ability to create objects with dynamic slots. This also figures out multi-values and uses a relational database table for the storage of the multi-values (so not serialized in the id column).
The reason for this is that we need to run queries against the multi values on a regular basis like "show me all persons that are have the following car", where car is a multivalue (as persons can have more than one car, albeit with todays gazoline prices ....).
If we instantiate all persons from the database upon server start, how quick is XoTCL in searching for objects where a slot has a certain value, even if multi-valued. Additionally the question is, if I can quickly search for objects whose slot is a specific other object (assume car was not a multiple choice value, but multi-valued reference to the car class).
The attribute definition should be strored in AMS (AMS or ACS? DAVEB) attributes and the object types should be acs object types to make it easier and reuse existing functionality. Once we agree on a single system, the need for extension of ams_attributes tables done by the exisiting packages won't be needed anymore, as we could generically extend ams_attributes.
As for the attributes itself, we have two storage options. BOTH should be implemented and defined in the Attribute generation where it is actually stored.
This is the way AMS stores it's data. You have ams tables that hold the attributes and depending on the settings of the attribute the options (if multiple choice) or the plain value. Additionally support for address and telephone number object type exists. As you can see this actually allows a hierarchy of object types (an object type can exist out of multiple other object types and not only the ones provided by the database).
- On the plus side is it's flexibility (no need to make changes to the database tables) and the ability to use subtypes.
- Additionally you can quickly add and remove options from a multiple choice attribute.
- A major drawback of this approach is the fact that the metadata tables can grow very large if you store all attributes in them (although in our CRM settings this so far was not an issue, knock on wood).
- Additionally adding the attributes into database selects can take it's time (as the stored PL/SQL functions to retrieve an attribute are slower than just querying a field in a database table). On the other hand, if used with the caching mechanisms provided in AMS and using template::multirow::sort instead of having listbuilder sort in the database, things get considerably sped up.
Dynamic Types stores the attributes in the object_types table as defined in acs_object_types. Alternatively you could specify a different table to use for the storing of the attribute, although this will delute one of the main benefits of DT, the fast access to the data.
See AMS minus
See AMS plus :-).
The api should provide you with procedures to
- Create a new object type
- Extend an existing object type with attributes
- For each attribute let you define where you want to store it and of what type the attribute is
- Choose the widget for displaying the attribute
- Retrieve the attributes value both in Tcl and pl/sql
- Extend ad_from and template::list so that it automatically allows you to display all attributes
- Support pages / ams_lists, to limit the display in ad_form and template::list to the attributes in the list
- Save all attributes of an object_type at once (needed when we deal with subtypes)
- Support for alternative storage areas for subtypes. E.g. postal-addresses is stored in the postal_address table. Same for ]po[ attributes.
- Support for external storage areas. Especially in the corporate world they have their own applications storing data. Instead of synchronizing it manually, have acs-attributes use the external storage.
A page in the context here (and please change it if you have a better idea) is what AMS calls lists. It allows you to group multiple attributes per object type so they can be entered in one go. As an example in contacts you can use pages for each group a person (object_type) belongs in, so depending on the group membership, only certain attributes can be edited or displayed. Additionally permissions can be granted on a page basis, therefore allowing only admins to enter admin relevant data. Though in contacts we do have need to provide permissions on a per page/object level (e.g all users can edit their own data except for attributes xyz stored in the pages abc), I don't think this is useful in a general way.
A second use case are projects, where you can have additional attributes depending on the project type. Combined with workflow this gives you a powerful tool where you can have a project undergo various stages and in each stage other attributes are relevant to be filled out, though the project itself is never losing the value of one of it's attributes in the process.
Furthermore, pages should support headings and allow the setting of required and default values for attributes (so the required tag and the default value can differ for an attribute, depending on which page it is used).
Additionally we should think about support for using display, template::list and form templates for each page, so we could modify how a page of attributes is displayed to a user.
Last but not least, we might want to have pages support display and editing of attributes from multiple object_types on the same page.
A user interface needs to exist so you can easily create a new object type and add attributes to existing object types. Furthermore support for creating pages needs to be there so you can limit the number of attributes displayed in a form/list and define the order in which they are displayed (form_entry_order, form_display_order, list_display_order, default_list_sort_order).
Listbuilder would need to change so we could (optional setting in page) allow the user to define which elements of a page he wants to have in his list. Furthermore, the sort order needs to take into account that we might have to sort by an attribute that is stored in metadata storage, so we would have to sort the list e.g.with template::list::sort. Last but not least, to make it easy for users, we should not have to rewrite every template::list statement to allow the display of additional attributes, so dynamic attribute support should hopefully come out of the box. Okay, this might just be too much of a goal, especially taking into account that lists usually combine multiple object types into one.
ad_form would need to be amended so it supports pages, meaning if called with a page name it will display all the attribute of the page. This is in addition to any elements already defined on the page, though for obvious reasons it should not display the same page name twice. If called with multiple pages, display the attributes of each page, beginning with the first in the list and making sure that you are not displaying a page twice. This is useful if you have in contacts a person in multiple groups (which relates to multiple pages) but you want to edit the attributes of all the pages of the groups he is a member in at the same time