AMS (Attribute Management System)

AMS lets developers (via tcl api) and site wide administrators (via the the ams admin UI) add attributes to acs_object. These attributes can be dynamically added at any time on a live system. AMS then helps you collect attribute information for these defined acs_objects via input forms and helps you present them to users via your website. Whenever AMS stores ams attribute information about an object it keeps track of changes made via the content repository. This way you can see who and when a user changed an object's attributes and are able to revert back to a previous state.

Defining an Attribute

Ams attributes can either be defined via the ams admin user interface or via the ams::attribute::new proc. Every ams_attribute has an ams_widget associated with it. ams_widgets define what type of information the attribute contains the information necessary to generate forms and save various funcationally different types of information. View the documentation for ams::attribute::new to see what types of widgets are available. In most cases using the ams::attribute::new proc will be too tedious to do, instead it would be a good idea to use the shorthand as defined in creating and ams_list.

AMS Lists

AMS stores attributes in ams_lists. These lists are an ordered collection of attributes and can be called upon a variety of ways. Ams_lists can be used to generate ad_forms, or return attribute information for use with your packages UI. The attributes associated with your acs_object can be returned as named variables in your calling environment, as an array or as a list via the ams::object::attribute::values proc.

To define an ams_list of the elements you use the ams::define_list. That procedure has extensive documentation about the nuances of defining an ams_list. For example, lets assume that you are developing a package called "contacts" with the object_type of "ct_contact" and you want to define a list to collect information about a contact. You might choose to run the following procedure in when your system restarts:

ams::define_list -package_key "contacts" \
        -object_type "ct_contact" \
        -list_name "contact_person" \
        -pretty_name "The Fields used to Add/Edit a Contact Person" \
        -attributes {
                {first_names textbox {First Name(s)} {First Names} required}
                {middle_names textbox {Middle Name(s)} {Middle Names}}
                {last_name textbox {Last Name} {Last Names} required}
                {email email {Email Address} {Email Addresses}}
                {url url {Website} {Websites}}
                {home_address address {Home Address} {Home Addresses}}
                {home_phone telecom_number {Home Phone} {Home Phones}}
                {gender radio {Gender} {Genders} {options {{Male} {Female}}}}
        }

This will create an ams_list, define any attributes that haven't previously been defined for the ct_contact object and order the list in the order the attributes are specified.

AMS and ad_form

You have two options when dealing with ams and ad_form. Shorthand and detailed.

Shorthand

Shorthands is a completely simple way of creating forms without many options. These forms must only contain attributes defined in an ams_list. The supplied object_id must already exist in the acs_object table. The shorthand procs is ams_form, which is simply a wrapper for ad_form. For example, to create and ad_form named "contact_person_ae" create a page contacts/www/contact-person-ae.tcl with the following content:

ad_page_contract {
} {
        {ct_contact_id:integer,notnull}
}
set title "Contact Person Add/Edit"
set context [list $title]

ams_form -package_key "contacts" \
         -object_type "ct_contact" \
         -list_name "contact_person" \
         -form_name "contact_person_ae" \
         -object_id $ct_contact_id \
         -return_url "./"

ad_return_template

The contacts/www/contact-person-ae.adp would contain

<master>
<property name="title">@title@</property">
<property name="context">@context@</property">

<formtemplate id="contact_person_ae"></formtemplate">

That's it. If this isn't flexible enough you can also go with the detailed method.

Detailed

For many application the AMS and ad_form shorthand will be too simplistic. For those situations, you can use ams to interface with ad_form. You need to define ad_from -form elements like this:

ad_form ... -form [ams::ad_form::elements -package_key "contacts" -object_type "ct_contact" -list_name "contact_person"] ...

Note that this procedure returns an ad form appropriate element list. If you intending to define other elements you will need to ad_from -extend -name form_name -form ...

In the ad_form -edit_request block put

ad_form ... -edit_request {
        ams::object::attribute::values -vars -object_id $object_id
    } ...

This returns the variables upvared into your page, i.e. the first_names attribute could be returned with a value of "Jane" and the last_name attribute with a value of "Doe"... etc. ad_from looks for all form elements and appropriately pre-fills the form with the given values.

In the -on_submit block you enter the following:

ad_from ... -on_submit {
        ams::ad_form::save \
            -package_key "contacts" \
            -object_type "ct_contact" \
            -list_name "contact_person" \
            -form_name "contact_person_ae" \
            -object_id $ct_contact_id
    }

This is how you interface with AMS and ad_form. You may also specify other code in the -form -on_submit and -on_submit blocks.

AMS and your package's UI

THIS SECTION NEEDS LOTS OF WORK

to display attributes you can call ams::object::attribute::values to get the results back as upvared variables, as an array or as a list however you want. So, if on the contact index package you do, for example

db_multirow -extend { first_names last_name email home_phone } get_contacts { select ct_contact_id from ct_contacts order by names } {
#      set first_names [ams::object::attribute::value object_id object_type attribute_name]
    set first_names [ams::object::attribute::value $ct_contact_id ct_contact first_names]
}

That's it, you can also get upvared values like this

db_multirow -extend { first_names last_name email home_phone } get_contacts { select ct_contact_id from ct_contacts order by names } {
    ams::object::attributes::values -names -varenv $object_id { first_names last_name email home_phone }
}

Anyways, that's how it integrates with other packages. I've made it pretty efficient and i think the integration is pretty straight forward. If you have any questions please feel free to ask. AMS takes care of ALL content repository stuff, so what AMS does is effectively make it easy to make ANY package use the content repository without a steep learning curve. I am continuing to develop AMS since it fits our institutional priorities right now, and i don't think contacts will be too much work once ams is working correctly. I am currently working on an ETP revision that uses AMS as the attribute store for all page attributes... this way pretty much all data on a system can be housed in AMS, and other package are then in charge of relational issues. I want to work on contacts, and hope to get to it as soon as this other stuff is done. My boss went on a 2 month study leave, so once this is done i'm completely in charge of my time.


AMS Lists

You specify permissions at list object instantiation time by specifying the context id for the ams_list object however you want, only admins of the list get to modify that list. this is all done through the tcl api. If you want a list to belong to only one object you can simply program your package to specify list names that are the id's of the object you are using.

this way you are assured unique list names for that object_type based on package_key.

if you want a standard template for an object type you can...