Forum OpenACS Development: TCL API for acs_object_types

Posted by Barry Books on
After reading about the TCL API for content repository I got inspired and wrote one for acs_object_types. The syntax is basically the same but it generates all the code to build the database table plus the infrastructure for an acs_object_type. I also implemented the beginnings of an object_type editor and the routines for a no code ad_form interface as well as template::list.

The idea is you can create acs_object_types with a GUI interface then write out the definition in either TCL or plsql. The TCL interface is very handy because it's database independent and it creates all the acs_object_type metadata for free. The form and list code build the data structures for ad_form and template:list from the metadata. For example to create a form for an object:

ad_form -name object_type -mode $form_mode \
        -form [object_type::ad_form -form -object_type $object_type] \
        -select_query [object_type::ad_form -select_query -object_type $object_type] \
        -edit_data [object_type::ad_form -edit_data -object_type $object_type]


<include src="/packages/object-types/lib/form" object_type="@object_type@>

or for a list

template::list::create \
        -name attributes \
        -multirow attributes \
        -elements [object_type::list -elements -object_type acs_attribute] \
        -filters {
                object_type {}
The code special cases acs_object_type and acs_attribute to make them appear as acs_object_types even though they are not. This allows the GUI to be built with the form generating code.

I built something similar for my previous project but I was not suitable for general release. The goal of this package is to build on top of the existing datamodel and templating system so it can be useful to a broad audience.


  • Implement enough of the ad_form interface to create and save any object_type
  • Allow objects to contain other objects. For example a contact could be a person and an address object.
  • Port to Postgres
  • Allow selecting of attributes to display
  • Make acs_attributes real objects and build permissions into the form builder

See here for a sample. The TCL Object Def link will generate PL/SQL from a TCL list. The other links show the beginning of an object_type editor and the form builder. Saves have been disabled so clicking around should be harmless. I'll be hacking on the code throughout the day so you might see a request error or two.


Posted by Don Baccus on
This is excellent ...

I was planning to TIP a slightly different approach, however ... which would be to have acs_object.create_type create the table if need be and for acs_object.create_attribute to create the attribute if necessary.  create_type would also create the id column with the proper foreign key as well.

In essence this means "migrate the above from content_type.create_type() etc to base objects", make them both consistent.

This would simplify the create object Tcl API and would make things consistent regardless if one choose to create object types that way or directly in SQL.

BTW this is why the sketched-out Tcl API for creating content types from an APM callback works - the underlying content_type SQL package does all the table and column definitions if they don't already exist.

As far as creating any object goes, you can use package_instantiate_object to do that - check out the latest version of notes/www/add-edit.tcl I committed a couple of days ago.  I've been planning to add a package_update_object proc as well (I've already added a package_exex_plsql proc so one can call del() and similar procs directly from Tcl).

Some of the things on your TODO list a fairly ambitious, i.e. composite object types ...

Posted by Don Baccus on
Also I think we can really just get by with a single object create type Tcl API ...

I'm going to write some TIPs now ... do you want to collaborate on some of this stuff, Barry?

Posted by Don Baccus on
Also ... there's already code to build form elements that exists in the CMS.  Part of the CR Tcl API work being discussed with between Dave Bauer, myself and Jun would include, in my mind at least, exposing that code usefully.

Rather than build ad_form -form snippets from attribute data I was planning on making use of that existing code (which is smart about default widgets for types which can be overridden for individual objects of that type, etc).  There's a bunch of smart code that already exists buried in the CMS and rather than re-invent, my thinking has been to re-use.

Likewise there's already code to fill a form with existing data from the CR views built for CR types.

And you can render an object of a type in HTML using existing code if you only know where to look for it and can figure out the confusing API style.

So a bunch of this stuff is there, waiting to be exposed in human-usable form, and indeed Jun's already exposed quite a bit of it in his BCMS API that we intend to migrate to the CR proper.

This code can be quite easily made to work with base object types I believe, though I won't have time to investigate further for another week and a half, i.e. after my return to the States.

Posted by Barry Books on
The previous version I wrote used object_types and attributes to build the metadata model first. At some point you could then generate the database code and run it. You could also modify the metadata later and generate the alter table statements. It seems like the CR and object_types should work the same way. I just started using the CR so I'm not all that familiar with it.

The previous version I wrote supported objects in objects to any depth although more than 4 is not really that practical. It also supported 1 or more via max_n_values. I did not use the templating system because it was too slow (we had hundreds of objects per form). I think ad_form will work fine for any reasonable form. There needs to be an storage mechanism similar to generic but supporting multiple values per object. I also implemented a not so generic storage that could store datatypes like numbers and dates in something other than a varchar(4000).

Posted by Don Baccus on
Well, generating text from attributes to pass to ad_form which then processes it is unlikely to be any faster than simply generating the form builder stuff from attributes directly the  way that the CMS code does.  The latter is, conceptually, less work.

In other words ...

attributes -> snippet processed by ad_form -> form builder


attributes -> form builder

should not be faster ... I think the smart CMS code probably doesn't cache, or if it does, not sufficiently and speed problems ought to be fixable.

I was planning to make it possible to call the attribute->form builder API from ad_form.  For instance by adding an "-object_type foo" section, relaxing the one-form-block-only restriction so that you mix "built by hand" form bits with auto-generated form bits in the same form.

Of course the one thing the CMS stuff has going for it is that you can generate and process the form without calling ad_form at all, if that's all you need to do.  Everything's there to do it automagically.

Posted by Don Baccus on
The CMS also already includes code for building types dynamically from a web UI ...

This isn't new news, the only thing new is that some of us have time to start breaking this stuff out in usable form rather than just sit around and talk about it as we've done the last year and a half or so (except Jun, who's put a lot of work into CR Tcl API stuff).

Anyway before tossing this stuff out and starting over, I'd like to investigate reusing it ... I know Karl Goldstein and friends put a lot of thought and work into it.

Posted by Barry Books on
I'm going to dig around CMS today. I'll look into it's form generation code. I would like to see a self documenting ad_form widget interface similar to the ad_page_contract validation system. It would be great if you could do something like ad_from::create_widget foo and have foo show up in the api-docs. They also need to be added to acs_datatypes so you can use them as datatypes in acs_attributes.

My previous system built the entire form then cached it because our forms often and hundreds of elements. I originally used the templating system but with hundreds of elements it took several seconds to build a form. I think that use was really a special case and most objects only have a handful of attributes.

A -object_type option to ad_form might be a good way to go especially if you could specify attributes and perhaps multiple objects

-object_types {
{bar {bar1 bar2}
Posted by Walter McGinnis on
I was just digging in the CMS code to see what Don was referring to. cms/tcl/form-proc.tcl.content::get_revision_form builds up template::element create statements based on metadata and evaluates them as it goes. I was thinking that instead this could be tweaked to write out a tcl file much like bcms can "publish" a template/datasource pair.

content::process_revision_form looks pretty cool, too. Probably a plenty to debug and bring up to date here, but there is definitely a fair amount of work already done.

Posted by Dave Bauer on

Has there been any update on a Tcl API for acs object types? I am starting to work on the Tcl API for the rest of the content repository and it would be nice to have a Tcl API for defining content types.

Posted by Barry Books on
Sorry I missed this post.

I have a version for Oracle that works well enough to use, but everytime I look at it I think it's the wrong approach. If acs_attributes/acs_object_types where acs_objects and created the database columes then the TCL api becomes: package_instantiate_object. Either way needs to create the columns, the only real issue would be that the acs_object_types table would need an acs_object_type_id column.

I'll gather the code up and post it somewhere. The one issue with acs_attribute creating tables is in Oracle you have to grant create table role to the user id.