Index: openacs-4/packages/dynamic-types/sql/postgresql/acs-dynamic-types-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/Attic/acs-dynamic-types-create.sql,v diff -u -N --- openacs-4/packages/dynamic-types/sql/postgresql/acs-dynamic-types-create.sql 14 Feb 2005 14:33:27 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,15 +0,0 @@ --- This is free software distributed under the terms of the GNU Public --- License. Full text of the license is available from the GNU Project: --- http://www.fsf.org/copyleft/gpl.html - --- @author Lee Denison (lee@thaum.net) --- --- @creation-date 2004-11-12 --- --- @cvs-id $Id: acs-dynamic-types-create.sql,v 1.1 2005/02/14 14:33:27 daveb Exp $ --- - -\i dynamic-types-create.sql -\i forms-create.sql -\i metadata-create.sql -\i cr-types-create.sql Index: openacs-4/packages/dynamic-types/sql/postgresql/cr-types-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/cr-types-create.sql,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/sql/postgresql/cr-types-create.sql 14 Feb 2005 14:33:27 -0000 1.1 +++ openacs-4/packages/dynamic-types/sql/postgresql/cr-types-create.sql 15 Feb 2005 13:55:34 -0000 1.2 @@ -7,7 +7,7 @@ PERFORM dtype_widget__register_form_widget( ''content_revision'', - ''standard'', + ''default'', ''title'', ''text'', ''t'', @@ -16,7 +16,7 @@ PERFORM dtype_widget__set_param_value( ''content_revision'', - ''standard'', + ''default'', ''title'', ''maxlength'', ''1000'', @@ -26,7 +26,7 @@ PERFORM dtype_widget__register_form_widget( ''content_revision'', - ''standard'', + ''default'', ''description'', ''textarea'', ''f'', @@ -35,7 +35,7 @@ PERFORM dtype_widget__set_param_value( ''content_revision'', - ''standard'', + ''default'', ''description'', ''cols'', ''40'', @@ -47,7 +47,7 @@ PERFORM dtype_widget__register_form_widget( ''image'', - ''standard'', + ''default'', ''width'', ''text'', ''f'', @@ -56,7 +56,7 @@ PERFORM dtype_widget__register_form_widget( ''image'', - ''standard'', + ''default'', ''height'', ''text'', ''f'', @@ -65,7 +65,7 @@ PERFORM dtype_widget__set_param_value( ''image'', - ''standard'', + ''default'', ''width'', ''size'', ''5'', @@ -75,7 +75,7 @@ PERFORM dtype_widget__set_param_value( ''image'', - ''standard'', + ''default'', ''height'', ''size'', ''5'', Index: openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql 15 Feb 2005 13:55:34 -0000 1.1 @@ -0,0 +1,610 @@ +-- Dynamic Types dynamic view generation. + +-- Based on cms code by Michael Pih (pihman@arsdigita.com) and +-- Karl Goldstein (karlg@arsdigita.com) + +select define_function_args('dynamic_type__create_type','object_type,supertype;acs_object,pretty_name,pretty_plural,table_name,id_column;XXX,name_method'); + +create or replace function dynamic_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar) +returns integer as ' +declare + p_object_type alias for $1; + p_supertype alias for $2; -- default ''acs_object'' + p_pretty_name alias for $3; + p_pretty_plural alias for $4; + p_table_name alias for $5; + p_id_column alias for $6; -- default ''XXX'' + p_name_method alias for $7; -- default null + v_table_exists_p boolean; + v_supertype_table acs_object_types.table_name%TYPE; +begin + + -- create the attribute table if not already created + + select count(*) > 0 into v_table_exists_p + from pg_class + where relname = lower(p_table_name); + + if NOT v_table_exists_p then + select table_name into v_supertype_table from acs_object_types + where object_type = p_supertype; + + execute ''create table '' || p_table_name || '' ('' || + p_id_column || '' integer primary key references '' || + v_supertype_table || '')''; + end if; + + PERFORM acs_object_type__create_type ( + p_object_type, + p_pretty_name, + p_pretty_plural, + p_supertype, + p_table_name, + p_id_column, + null, + ''f'', + null, + p_name_method + ); + + PERFORM dynamic_type__refresh_view(p_object_type); + + return 0; +end;' language 'plpgsql'; + +select define_function_args('dynamic_type__drop_type','object_type,drop_children_p;f,drop_table_p;f'); + +create or replace function dynamic_type__drop_type (varchar,boolean,boolean) +returns integer as ' +declare + p_object_type alias for $1; + p_drop_children_p alias for $2; -- default ''f'' + p_drop_table_p alias for $3; -- default ''f'' + table_exists_p boolean; + v_table_name varchar; + is_subclassed_p boolean; + child_rec record; + attr_row record; +begin + + -- first we''ll rid ourselves of any dependent child types, if any , + -- along with their own dependent grandchild types + + select + count(*) > 0 into is_subclassed_p + from + acs_object_types + where supertype = p_object_type; + + -- this is weak and will probably break; + -- to remove grand child types, the process will probably + -- require some sort of querying for drop_type + -- methods within the children''s packages to make + -- certain there are no additional unanticipated + -- restraints preventing a clean drop + + if p_drop_children_p and is_subclassed_p then + + for child_rec in select + object_type + from + acs_object_types + where + supertype = p_object_type + LOOP + PERFORM dynamic_type__drop_type(child_rec.object_type, + ''t'', + p_drop_table_p); + end LOOP; + + end if; + + -- now drop all the attributes related to this type + for attr_row in select + attribute_name + from + acs_attributes + where + object_type = p_object_type + LOOP + PERFORM dynamic_type__drop_attribute(p_object_type, + attr_row.attribute_name, + ''f'' + ); + end LOOP; + + -- we''ll remove the associated table if it exists + select + table_exists(lower(table_name)) into table_exists_p + from + acs_object_types + where + object_type = p_object_type; + + if table_exists_p and p_drop_table_p then + select + table_name into v_table_name + from + acs_object_types + where + object_type = p_object_type; + + -- drop the rule and input/output views for the type + -- being dropped. + -- FIXME: this did not exist in the oracle code and it needs to be + -- tested. Thanks to Vinod Kurup for pointing this out. + -- The rule dropping might be redundant as the rule might be dropped + -- when the view is dropped. + + -- different syntax for dropping a rule in 7.2 and 7.3 so check which + -- version is being used (olah). + + if version() like ''%7.2%'' then + execute ''drop rule '' || v_table_name || ''_r''; + else + -- 7.3 syntax + execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; + end if; + + execute ''drop view '' || v_table_name || ''x''; + execute ''drop view '' || v_table_name || ''i''; + + execute ''drop table '' || v_table_name; + end if; + + PERFORM acs_object_type__drop_type(p_object_type, ''f''); + + return 0; +end;' language 'plpgsql'; + +select define_function_args('dynamic_type__create_attribute','object_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); + +-- function create_attribute +create or replace function dynamic_type__create_attribute (varchar,varchar,varchar,varchar,varchar,integer,varchar,varchar) +returns integer as ' +declare + p_object_type alias for $1; + p_attribute_name alias for $2; + p_datatype alias for $3; + p_pretty_name alias for $4; + p_pretty_plural alias for $5; -- default null + p_sort_order alias for $6; -- default null + p_default_value alias for $7; -- default null + p_column_spec alias for $8; -- default ''text'' + v_attr_id acs_attributes.attribute_id%TYPE; + v_table_name acs_object_types.table_name%TYPE; + v_column_exists boolean; +begin + + -- add the appropriate column to the table + + select table_name into v_table_name from acs_object_types + where object_type = p_object_type; + + if NOT FOUND then + raise EXCEPTION ''-20000: Object type % does not exist in dynamic_type.create_attribute'', p_object_type; + end if; + + select count(*) > 0 into v_column_exists + from pg_class c, pg_attribute a + where c.relname::varchar = v_table_name + and c.oid = a.attrelid + and a.attname = lower(p_attribute_name); + + if NOT v_column_exists then + execute ''alter table '' || v_table_name || '' add '' || + p_attribute_name || '' '' + || p_column_spec; + end if; + + v_attr_id := acs_attribute__create_attribute ( + p_object_type, + p_attribute_name, + p_datatype, + p_pretty_name, + p_pretty_plural, + null, + null, + p_default_value, + 1, + 1, + p_sort_order, + ''type_specific'', + ''f'' + ); + + PERFORM dynamic_type__refresh_view(p_object_type); + + return v_attr_id; + +end;' language 'plpgsql'; + + +-- procedure drop_attribute + +select define_function_args('dynamic_type__drop_attribute','object_type,attribute_name,drop_column;f'); + +create or replace function dynamic_type__drop_attribute (varchar,varchar,boolean) +returns integer as ' +declare + p_object_type alias for $1; + p_attribute_name alias for $2; + p_drop_column alias for $3; -- default ''f'' + v_attr_id acs_attributes.attribute_id%TYPE; + v_table acs_object_types.table_name%TYPE; +begin + + -- Get attribute information + select + upper(t.table_name), a.attribute_id + into + v_table, v_attr_id + from + acs_object_types t, acs_attributes a + where + t.object_type = p_object_type + and + a.object_type = p_object_type + and + a.attribute_name = p_attribute_name; + + if NOT FOUND then + raise EXCEPTION ''-20000: Attribute %:% does not exist in dynamic_type.drop_attribute'', p_object_type, p_attribute_name; + end if; + + -- Drop the attribute + PERFORM acs_attribute__drop_attribute(p_object_type, + p_attribute_name); + + -- Drop the column if neccessary + if p_drop_column then + execute ''alter table '' || v_table || '' drop column '' || + p_attribute_name || '' cascade''; + end if; + + PERFORM dynamic_type__refresh_view(p_object_type); + + return 0; +end;' language 'plpgsql'; + + +-- function trigger_insert_statement +create or replace function dynamic_type__trigger_insert_statement (varchar) +returns varchar as ' +declare + p_object_type alias for $1; + v_table_name acs_object_types.table_name%TYPE; + v_id_column acs_object_types.id_column%TYPE; + cols varchar default ''''; + vals varchar default ''''; + attr_rec record; +begin + if p_object_type is null then + return exception ''dynamic_type__trigger_insert_statement called with null object_type''; + end if; + + select + table_name, id_column into v_table_name, v_id_column + from + acs_object_types + where + object_type = p_object_type; + + for attr_rec in select + attribute_name + from + acs_attributes + where + object_type = p_object_type + LOOP + cols := cols || '', '' || attr_rec.attribute_name; + vals := vals || '', new.'' || attr_rec.attribute_name; + end LOOP; + + return ''insert into '' || v_table_name || + '' ( '' || v_id_column || cols || '' ) values (dt_dummy.val'' || + vals || '')''; + +end;' language 'plpgsql' stable; + +-- function trigger_update_statement +create or replace function dynamic_type__trigger_update_statement (varchar) +returns varchar as ' +declare + p_object_type alias for $1; + v_table_name acs_object_types.table_name%TYPE; + v_id_column acs_object_types.id_column%TYPE; + cols varchar default ''''; + attr_rec record; + v_count integer; +begin + if p_object_type is null then + return exception ''dynamic_type__trigger_update_statement called with null object_type''; + end if; + + select + table_name, id_column into v_table_name, v_id_column + from + acs_object_types + where + object_type = p_object_type; + + v_count := 0; + for attr_rec in select + attribute_name + from + acs_attributes + where + object_type = p_object_type + LOOP + if v_count > 0 then + cols := cols || '', ''; + end if; + + cols := cols || attr_rec.attribute_name || '' = new.'' || attr_rec.attribute_name; + + v_count := v_count + 1; + end LOOP; + + if v_count > 0 then + return ''update '' || v_table_name || + '' set '' || cols || '' where '' || + v_id_column || '' = old.'' || v_id_column; + else + return ''''; + end if; + +end;' language 'plpgsql' stable; + +-- dummy table provides a target for updates in dynamically generated trigger +-- statements. If type is acs_object or cr_revisions then rule would end up +-- having only a select statement which causes an error to be thrown by the +-- dml command. dml command checks for NS_ROWS result and throws an error if +-- found. Using a dummy update causes NS_OK to be returned which satisfies +-- the dml result checking. + +-- DCW, 2001-06-09 + +create table dt_dummy ( + val integer +); + +insert into dt_dummy (val) values (null); + +create function dt_dummy_ins_del_tr () returns trigger as ' +begin + raise execption ''Only updates are allowed on dt_dummy''; + return null; +end;' language 'plpgsql'; + +create trigger dt_dummy_ins_del_tr before insert or delete on +dt_dummy for each row execute procedure dt_dummy_ins_del_tr (); + + +-- FIXME: need to look at this in more detail. This probably can't be made +-- to work reliably in postgresql. Currently we are using a rule to insert +-- into the input view when a new content revision is added. Pg locks the +-- underlying table when the rule is dropped, so the dropping and recreating +-- of the new content revisons seems like it would be reliable, but the +-- possiblity of a race condition exists for either the initial creation +-- or dropping of a type. I'm not sure if the possibility of a race condition +-- actually exists in practice. The thing to do here might be to just create +-- a function that dynamically builds the insert strings and does the +-- each time an insert is done on the content_type view. Trade-off being +-- that the inserts would be slower due to the use of dynamic code in pl/psql. +-- More digging required ... + +-- DCW, 2001-03-30. + +-- Create or replace a trigger on insert for simplifying addition of +-- object instances, with special handling code for content revision subtypes + +-- procedure refresh_trigger +create or replace function dynamic_type__refresh_trigger (varchar) +returns integer as ' +declare + p_object_type alias for $1; + insert_rule_text text default ''''; + update_rule_text text default ''''; + v_content_revision_p boolean; + v_table_name acs_object_types.table_name%TYPE; + type_rec record; +begin + + -- get the table name for the object type (determines view name) + + select table_name + into v_table_name + from acs_object_types + where object_type = p_object_type; + + select (case when p_object_type = ''content_revision'' then 1 + else 0 end) into v_content_revision_p + from dual; + + if not v_content_revision_p then + select count(*) > 0 into v_content_revision_p + from acs_object_type_supertype_map + where object_type = p_object_type + and ancestor_type = ''content_revision''; + end if; + + -- + -- start building rule code + -- + insert_rule_text := ''create rule '' || v_table_name || + ''_ir as on insert to '' || v_table_name || ''i do instead (''; + + update_rule_text := ''create rule '' || v_table_name || + ''_ur as on update to '' || v_table_name || ''i do instead (''; + + -- if we are dealing with content revisions then add handler code + + if v_content_revision_p then + insert_rule_text := insert_rule_text || ''update dt_dummy set val = ( + select content_revision__new( + new.title, + new.description, + now(), + new.mime_type, + new.nls_language, + null, + content_symlink__resolve(new.item_id), + new.revision_id, + now(), + new.creation_user, + new.creation_ip + ));''; + else + insert_rule_text := insert_rule_text || ''update dt_dummy set val = ( + select acs_object__new( + null, + new.object_type, + now(), + new.creation_user, + new.creation_ip, + null, + ''''t'''' + ));''; + end if; + + -- add an insert statement for each subtype in the hierarchy for this type + + for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level + from acs_object_types ot1, acs_object_types ot2 + where ot1.object_type = p_object_type + and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) + order by level desc + loop + if not (type_rec.object_type = ''acs_object'') then + if not (type_rec.object_type = ''content_revision'') then + insert_rule_text := insert_rule_text || '' '' || dynamic_type__trigger_insert_statement(type_rec.object_type) || '';''; + end if; + + update_rule_text := update_rule_text || '' '' || dynamic_type__trigger_update_statement(type_rec.object_type) || '';''; + end if; + end loop; + + -- end building the rule definition code + + insert_rule_text := insert_rule_text || '' );''; + update_rule_text := update_rule_text || '' );''; + + -- + -- done building rule code + -- + + -- drop the old rule + if rule_exists(v_table_name || ''_ir'', v_table_name || ''i'') then + + -- different syntax for dropping a rule in 7.2 and 7.3 so check which + -- version is being used (olah). + if version() like ''%7.2%'' then + execute ''drop rule '' || v_table_name || ''_ir''; + execute ''drop rule '' || v_table_name || ''_ur''; + else + -- 7.3 syntax + execute ''drop rule '' || v_table_name || ''_ir on '' || v_table_name || ''i''; + execute ''drop rule '' || v_table_name || ''_ur on '' || v_table_name || ''i''; + end if; + + end if; + + -- create the new rule for inserts on the content type + execute insert_rule_text; + execute update_rule_text; + + return null; + +end;' language 'plpgsql'; + + +-- procedure refresh_view +create or replace function dynamic_type__refresh_view (varchar) +returns integer as ' +declare + p_object_type alias for $1; + cols varchar default ''''; + tabs varchar default ''''; + joins varchar default ''''; + v_table_name varchar; + v_content_revision_p boolean; + join_rec record; +begin + select (case when p_object_type = ''content_revision'' then 1 + else 0 end) into v_content_revision_p + from dual; + + if not v_content_revision_p then + select count(*) > 0 into v_content_revision_p + from acs_object_type_supertype_map + where object_type = p_object_type + and ancestor_type = ''content_revision''; + end if; + + for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level + from acs_object_types ot1, acs_object_types ot2 + where ot2.object_type <> ''acs_object'' + and ot2.object_type <> ''content_revision'' + and ot1.object_type = p_object_type + and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) + order by ot2.tree_sortkey desc + loop + cols := cols || '', '' || join_rec.table_name || ''.*''; + tabs := tabs || '', '' || join_rec.table_name; + joins := joins || '' and acs_objects.object_id = '' || + join_rec.table_name || ''.'' || join_rec.id_column; + end loop; + + select table_name into v_table_name from acs_object_types + where object_type = p_object_type; + + if length(v_table_name) > 25 then + raise exception ''Table name cannot be longer than 25 characters, because that causes conflicting rules when we create the views.''; + end if; + + -- create the input view (includes content columns) + + if table_exists(v_table_name || ''i'') then + execute ''drop view '' || v_table_name || ''i''; + end if; + + -- FIXME: need to look at content_revision__get_content. Since the CR + -- can store data in a lob, a text field or in an external file, getting + -- the data attribute for this view will be problematic. + + if not v_content_revision_p then + execute ''create view '' || v_table_name || + ''i as select acs_objects.object_id, acs_objects.object_type, + acs_objects.package_id, acs_objects.title, + acs_objects.context_id, acs_objects.security_inherit_p, + acs_objects.creation_user, acs_objects.creation_date, + acs_objects.creation_ip, acs_objects.last_modified, + acs_objects.modifying_user, acs_objects.modifying_ip, + acs_objects.tree_sortkey, acs_objects.max_child_sortkey'' || cols || + '' from acs_objects'' || tabs || + '' where acs_objects.object_id is not null'' || joins; + else + -- we don''t include acs_object.title below because it should be the same + -- as cr_item.title - the relationship will be maintained for inserts and + -- updates on this view + execute ''create view '' || v_table_name || + ''i as select acs_objects.object_id, acs_objects.object_type, + acs_objects.package_id, acs_objects.title as object_title, + acs_objects.context_id, acs_objects.security_inherit_p, + acs_objects.creation_user, acs_objects.creation_date, + acs_objects.creation_ip, acs_objects.last_modified, + acs_objects.modifying_user, acs_objects.modifying_ip, + acs_objects.tree_sortkey, acs_objects.max_child_sortkey, + cr.revision_id, cr.title, cr.item_id, + cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || + cols || + '' from acs_objects, cr_revisions cr'' || tabs || + '' where acs_objects.object_id = cr.revision_id '' || joins; + end if; + + PERFORM dynamic_type__refresh_trigger(p_object_type); + + return 0; +end;' language 'plpgsql'; +-- show errors Index: openacs-4/packages/dynamic-types/sql/postgresql/dynamic-types-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/dynamic-types-create.sql,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/sql/postgresql/dynamic-types-create.sql 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/sql/postgresql/dynamic-types-create.sql 15 Feb 2005 13:55:34 -0000 1.2 @@ -1,609 +1,15 @@ --- Dynamic Types dynamic view generation. +-- This is free software distributed under the terms of the GNU Public +-- License. Full text of the license is available from the GNU Project: +-- http://www.fsf.org/copyleft/gpl.html --- Based on cms code by Michael Pih (pihman@arsdigita.com) and --- Karl Goldstein (karlg@arsdigita.com) +-- @author Lee Denison (lee@thaum.net) +-- +-- @creation-date 2004-11-12 +-- +-- @cvs-id $Id$ +-- -select define_function_args('dynamic_type__create_type','object_type,supertype;acs_object,pretty_name,pretty_plural,table_name,id_column;XXX,name_method'); - -create or replace function dynamic_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar) -returns integer as ' -declare - p_object_type alias for $1; - p_supertype alias for $2; -- default ''acs_object'' - p_pretty_name alias for $3; - p_pretty_plural alias for $4; - p_table_name alias for $5; - p_id_column alias for $6; -- default ''XXX'' - p_name_method alias for $7; -- default null - v_table_exists_p boolean; - v_supertype_table acs_object_types.table_name%TYPE; -begin - - -- create the attribute table if not already created - - select count(*) > 0 into v_table_exists_p - from pg_class - where relname = lower(p_table_name); - - if NOT v_table_exists_p then - select table_name into v_supertype_table from acs_object_types - where object_type = p_supertype; - - execute ''create table '' || p_table_name || '' ('' || - p_id_column || '' integer primary key references '' || - v_supertype_table || '')''; - end if; - - PERFORM acs_object_type__create_type ( - p_object_type, - p_pretty_name, - p_pretty_plural, - p_supertype, - p_table_name, - p_id_column, - null, - ''f'', - null, - p_name_method - ); - - PERFORM dynamic_type__refresh_view(p_object_type); - - return 0; -end;' language 'plpgsql'; - -select define_function_args('dynamic_type__drop_type','object_type,drop_children_p;f,drop_table_p;f'); - -create or replace function dynamic_type__drop_type (varchar,boolean,boolean) -returns integer as ' -declare - p_object_type alias for $1; - p_drop_children_p alias for $2; -- default ''f'' - p_drop_table_p alias for $3; -- default ''f'' - table_exists_p boolean; - v_table_name varchar; - is_subclassed_p boolean; - child_rec record; - attr_row record; -begin - - -- first we''ll rid ourselves of any dependent child types, if any , - -- along with their own dependent grandchild types - - select - count(*) > 0 into is_subclassed_p - from - acs_object_types - where supertype = p_object_type; - - -- this is weak and will probably break; - -- to remove grand child types, the process will probably - -- require some sort of querying for drop_type - -- methods within the children''s packages to make - -- certain there are no additional unanticipated - -- restraints preventing a clean drop - - if p_drop_children_p and is_subclassed_p then - - for child_rec in select - object_type - from - acs_object_types - where - supertype = p_object_type - LOOP - PERFORM dynamic_type__drop_type(child_rec.object_type, - ''t'', - p_drop_table_p); - end LOOP; - - end if; - - -- now drop all the attributes related to this type - for attr_row in select - attribute_name - from - acs_attributes - where - object_type = p_object_type - LOOP - PERFORM dynamic_type__drop_attribute(p_object_type, - attr_row.attribute_name, - ''f'' - ); - end LOOP; - - -- we''ll remove the associated table if it exists - select - table_exists(lower(table_name)) into table_exists_p - from - acs_object_types - where - object_type = p_object_type; - - if table_exists_p and p_drop_table_p then - select - table_name into v_table_name - from - acs_object_types - where - object_type = p_object_type; - - -- drop the rule and input/output views for the type - -- being dropped. - -- FIXME: this did not exist in the oracle code and it needs to be - -- tested. Thanks to Vinod Kurup for pointing this out. - -- The rule dropping might be redundant as the rule might be dropped - -- when the view is dropped. - - -- different syntax for dropping a rule in 7.2 and 7.3 so check which - -- version is being used (olah). - - if version() like ''%7.2%'' then - execute ''drop rule '' || v_table_name || ''_r''; - else - -- 7.3 syntax - execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; - end if; - - execute ''drop view '' || v_table_name || ''x''; - execute ''drop view '' || v_table_name || ''i''; - - execute ''drop table '' || v_table_name; - end if; - - PERFORM acs_object_type__drop_type(p_object_type, ''f''); - - return 0; -end;' language 'plpgsql'; - -select define_function_args('dynamic_type__create_attribute','object_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); - --- function create_attribute -create or replace function dynamic_type__create_attribute (varchar,varchar,varchar,varchar,varchar,integer,varchar,varchar) -returns integer as ' -declare - p_object_type alias for $1; - p_attribute_name alias for $2; - p_datatype alias for $3; - p_pretty_name alias for $4; - p_pretty_plural alias for $5; -- default null - p_sort_order alias for $6; -- default null - p_default_value alias for $7; -- default null - p_column_spec alias for $8; -- default ''text'' - v_attr_id acs_attributes.attribute_id%TYPE; - v_table_name acs_object_types.table_name%TYPE; - v_column_exists boolean; -begin - - -- add the appropriate column to the table - - select table_name into v_table_name from acs_object_types - where object_type = p_object_type; - - if NOT FOUND then - raise EXCEPTION ''-20000: Object type % does not exist in dynamic_type.create_attribute'', p_object_type; - end if; - - select count(*) > 0 into v_column_exists - from pg_class c, pg_attribute a - where c.relname::varchar = v_table_name - and c.oid = a.attrelid - and a.attname = lower(p_attribute_name); - - if NOT v_column_exists then - execute ''alter table '' || v_table_name || '' add '' || - p_attribute_name || '' '' - || p_column_spec; - end if; - - v_attr_id := acs_attribute__create_attribute ( - p_object_type, - p_attribute_name, - p_datatype, - p_pretty_name, - p_pretty_plural, - null, - null, - p_default_value, - 1, - 1, - p_sort_order, - ''type_specific'', - ''f'' - ); - - PERFORM dynamic_type__refresh_view(p_object_type); - - return v_attr_id; - -end;' language 'plpgsql'; - - --- procedure drop_attribute - -select define_function_args('dynamic_type__drop_attribute','object_type,attribute_name,drop_column;f'); - -create or replace function dynamic_type__drop_attribute (varchar,varchar,boolean) -returns integer as ' -declare - p_object_type alias for $1; - p_attribute_name alias for $2; - p_drop_column alias for $3; -- default ''f'' - v_attr_id acs_attributes.attribute_id%TYPE; - v_table acs_object_types.table_name%TYPE; -begin - - -- Get attribute information - select - upper(t.table_name), a.attribute_id - into - v_table, v_attr_id - from - acs_object_types t, acs_attributes a - where - t.object_type = p_object_type - and - a.object_type = p_object_type - and - a.attribute_name = p_attribute_name; - - if NOT FOUND then - raise EXCEPTION ''-20000: Attribute %:% does not exist in dynamic_type.drop_attribute'', p_object_type, p_attribute_name; - end if; - - -- Drop the attribute - PERFORM acs_attribute__drop_attribute(p_object_type, - p_attribute_name); - - -- Drop the column if neccessary - if p_drop_column then - execute ''alter table '' || v_table || '' drop column '' || - p_attribute_name || '' cascade''; - end if; - - PERFORM dynamic_type__refresh_view(p_object_type); - - return 0; -end;' language 'plpgsql'; - - --- function trigger_insert_statement -create or replace function dynamic_type__trigger_insert_statement (varchar) -returns varchar as ' -declare - p_object_type alias for $1; - v_table_name acs_object_types.table_name%TYPE; - v_id_column acs_object_types.id_column%TYPE; - cols varchar default ''''; - vals varchar default ''''; - attr_rec record; -begin - if p_object_type is null then - return exception ''dynamic_type__trigger_insert_statement called with null object_type''; - end if; - - select - table_name, id_column into v_table_name, v_id_column - from - acs_object_types - where - object_type = p_object_type; - - for attr_rec in select - attribute_name - from - acs_attributes - where - object_type = p_object_type - LOOP - cols := cols || '', '' || attr_rec.attribute_name; - vals := vals || '', new.'' || attr_rec.attribute_name; - end LOOP; - - return ''insert into '' || v_table_name || - '' ( '' || v_id_column || cols || '' ) values (dt_dummy.val'' || - vals || '')''; - -end;' language 'plpgsql' stable; - --- function trigger_update_statement -create or replace function dynamic_type__trigger_update_statement (varchar) -returns varchar as ' -declare - p_object_type alias for $1; - v_table_name acs_object_types.table_name%TYPE; - v_id_column acs_object_types.id_column%TYPE; - cols varchar default ''''; - attr_rec record; - v_count integer; -begin - if p_object_type is null then - return exception ''dynamic_type__trigger_update_statement called with null object_type''; - end if; - - select - table_name, id_column into v_table_name, v_id_column - from - acs_object_types - where - object_type = p_object_type; - - v_count := 0; - for attr_rec in select - attribute_name - from - acs_attributes - where - object_type = p_object_type - LOOP - if v_count > 0 then - cols := cols || '', ''; - end if; - - cols := cols || attr_rec.attribute_name || '' = new.'' || attr_rec.attribute_name; - - v_count := v_count + 1; - end LOOP; - - if v_count > 0 then - return ''update '' || v_table_name || - '' set '' || cols || '' where '' || - v_id_column || '' = old.'' || v_id_column; - else - return ''''; - end if; - -end;' language 'plpgsql' stable; - --- dummy table provides a target for updates in dynamically generated trigger --- statements. If type is acs_object or cr_revisions then rule would end up --- having only a select statement which causes an error to be thrown by the --- dml command. dml command checks for NS_ROWS result and throws an error if --- found. Using a dummy update causes NS_OK to be returned which satisfies --- the dml result checking. - --- DCW, 2001-06-09 - -create table dt_dummy ( - val integer -); - -insert into dt_dummy (val) values (null); - -create function dt_dummy_ins_del_tr () returns trigger as ' -begin - raise execption ''Only updates are allowed on dt_dummy''; - return null; -end;' language 'plpgsql'; - -create trigger dt_dummy_ins_del_tr before insert or delete on -dt_dummy for each row execute procedure dt_dummy_ins_del_tr (); - - --- FIXME: need to look at this in more detail. This probably can't be made --- to work reliably in postgresql. Currently we are using a rule to insert --- into the input view when a new content revision is added. Pg locks the --- underlying table when the rule is dropped, so the dropping and recreating --- of the new content revisons seems like it would be reliable, but the --- possiblity of a race condition exists for either the initial creation --- or dropping of a type. I'm not sure if the possibility of a race condition --- actually exists in practice. The thing to do here might be to just create --- a function that dynamically builds the insert strings and does the --- each time an insert is done on the content_type view. Trade-off being --- that the inserts would be slower due to the use of dynamic code in pl/psql. --- More digging required ... - --- DCW, 2001-03-30. - --- Create or replace a trigger on insert for simplifying addition of --- object instances, with special handling code for content revision subtypes - --- procedure refresh_trigger -create or replace function dynamic_type__refresh_trigger (varchar) -returns integer as ' -declare - p_object_type alias for $1; - insert_rule_text text default ''''; - update_rule_text text default ''''; - v_content_revision_p boolean; - v_table_name acs_object_types.table_name%TYPE; - type_rec record; -begin - - -- get the table name for the object type (determines view name) - - select table_name - into v_table_name - from acs_object_types - where object_type = p_object_type; - - select (case when p_object_type = ''content_revision'' then 1 - else 0 end) into v_content_revision_p - from dual; - - if not v_content_revision_p then - select count(*) > 0 into v_content_revision_p - from acs_object_type_supertype_map - where object_type = p_object_type - and ancestor_type = ''content_revision''; - end if; - - -- - -- start building rule code - -- - insert_rule_text := ''create rule '' || v_table_name || - ''_ir as on insert to '' || v_table_name || ''i do instead (''; - - update_rule_text := ''create rule '' || v_table_name || - ''_ur as on update to '' || v_table_name || ''i do instead (''; - - -- if we are dealing with content revisions then add handler code - - if v_content_revision_p then - insert_rule_text := insert_rule_text || ''update dt_dummy set val = ( - select content_revision__new( - new.title, - new.description, - now(), - new.mime_type, - new.nls_language, - null, - content_symlink__resolve(new.item_id), - new.revision_id, - now(), - new.creation_user, - new.creation_ip - ));''; - else - insert_rule_text := insert_rule_text || ''update dt_dummy set val = ( - select acs_object__new( - null, - new.object_type, - now(), - new.creation_user, - new.creation_ip, - null, - ''''t'''' - ));''; - end if; - - -- add an insert statement for each subtype in the hierarchy for this type - - for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level - from acs_object_types ot1, acs_object_types ot2 - where ot1.object_type = p_object_type - and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) - order by level desc - loop - if not (type_rec.object_type = ''acs_object'') and - not (type_rec.object_type = ''content_revision'') then - insert_rule_text := insert_rule_text || '' '' || dynamic_type__trigger_insert_statement(type_rec.object_type) || '';''; - end if; - - update_rule_text := update_rule_text || '' '' || dynamic_type__trigger_update_statement(type_rec.object_type) || '';''; - end loop; - - -- end building the rule definition code - - insert_rule_text := insert_rule_text || '' );''; - update_rule_text := update_rule_text || '' );''; - - -- - -- done building rule code - -- - - -- drop the old rule - if rule_exists(v_table_name || ''_ir'', v_table_name || ''i'') then - - -- different syntax for dropping a rule in 7.2 and 7.3 so check which - -- version is being used (olah). - if version() like ''%7.2%'' then - execute ''drop rule '' || v_table_name || ''_ir''; - execute ''drop rule '' || v_table_name || ''_ur''; - else - -- 7.3 syntax - execute ''drop rule '' || v_table_name || ''_ir on '' || v_table_name || ''i''; - execute ''drop rule '' || v_table_name || ''_ur on '' || v_table_name || ''i''; - end if; - - end if; - - -- create the new rule for inserts on the content type - execute insert_rule_text; - execute update_rule_text; - - return null; - -end;' language 'plpgsql'; - - --- procedure refresh_view -create or replace function dynamic_type__refresh_view (varchar) -returns integer as ' -declare - p_object_type alias for $1; - cols varchar default ''''; - tabs varchar default ''''; - joins varchar default ''''; - v_table_name varchar; - v_content_revision_p boolean; - join_rec record; -begin - select (case when p_object_type = ''content_revision'' then 1 - else 0 end) into v_content_revision_p - from dual; - - if not v_content_revision_p then - select count(*) > 0 into v_content_revision_p - from acs_object_type_supertype_map - where object_type = p_object_type - and ancestor_type = ''content_revision''; - end if; - - for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level - from acs_object_types ot1, acs_object_types ot2 - where ot2.object_type <> ''acs_object'' - and ot2.object_type <> ''content_revision'' - and ot1.object_type = p_object_type - and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) - order by ot2.tree_sortkey desc - loop - cols := cols || '', '' || join_rec.table_name || ''.*''; - tabs := tabs || '', '' || join_rec.table_name; - joins := joins || '' and acs_objects.object_id = '' || - join_rec.table_name || ''.'' || join_rec.id_column; - end loop; - - select table_name into v_table_name from acs_object_types - where object_type = p_object_type; - - if length(v_table_name) > 25 then - raise exception ''Table name cannot be longer than 25 characters, because that causes conflicting rules when we create the views.''; - end if; - - -- create the input view (includes content columns) - - if table_exists(v_table_name || ''i'') then - execute ''drop view '' || v_table_name || ''i''; - end if; - - -- FIXME: need to look at content_revision__get_content. Since the CR - -- can store data in a lob, a text field or in an external file, getting - -- the data attribute for this view will be problematic. - - -- TODO: add the columns below for acs_objects when this is rolled - -- forward to 5.2 - -- acs_objects.package_id as object_package_id, - -- acs_objects.title as object_title, - - if not v_content_revision_p then - execute ''create view '' || v_table_name || - ''i as select acs_objects.object_id, acs_objects.object_type, - acs_objects.context_id, acs_objects.security_inherit_p, - acs_objects.creation_user, acs_objects.creation_date, - acs_objects.creation_ip, acs_objects.last_modified, - acs_objects.modifying_user, acs_objects.modifying_ip, - acs_objects.tree_sortkey, acs_objects.max_child_sortkey'' || cols || - '' from acs_objects'' || tabs || - '' where acs_objects.object_id is not null'' || joins; - else - execute ''create view '' || v_table_name || - ''i as select acs_objects.object_id, acs_objects.object_type, - acs_objects.context_id, acs_objects.security_inherit_p, - acs_objects.creation_user, acs_objects.creation_date, - acs_objects.creation_ip, acs_objects.last_modified, - acs_objects.modifying_user, acs_objects.modifying_ip, - acs_objects.tree_sortkey, acs_objects.max_child_sortkey, - cr.revision_id, cr.title, cr.item_id, - cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || - cols || - '' from acs_objects, cr_revisions cr'' || tabs || - '' where acs_objects.object_id = cr.revision_id '' || joins; - end if; - - PERFORM dynamic_type__refresh_trigger(p_object_type); - - return 0; -end;' language 'plpgsql'; --- show errors +\i dtype-package-create.sql +\i forms-create.sql +\i metadata-create.sql +\i cr-types-create.sql Index: openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql 15 Feb 2005 13:55:34 -0000 1.2 @@ -276,7 +276,7 @@ --------------------------------------------- -- This view contains the elements of all defined forms plus the elements of a --- 'default' form for all object_types that have metadata. +-- 'implicit' form for all object_types that have metadata. create view dtype_form_elements_all as select a.attribute_id, @@ -320,7 +320,7 @@ a.static_p, a.column_name, null as form_id, - 'default' as form_name, + 'implicit' as form_name, null as element_id, wt.widget, (case when a.min_n_values > 0 then TRUE else FALSE end) as is_required @@ -334,7 +334,7 @@ -- This view contains all defined element parameters, any default parameters -- each element has by virtue of its datatype and any default parameters each -- element has by virtue of its widget type in order of precedence. It --- includes parameters for the 'default' forms defined in the view above. +-- includes parameters for the 'implicit' forms defined in the view above. create view dtype_element_params_all as select e.element_id, Index: openacs-4/packages/dynamic-types/sql/postgresql/metadata-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/metadata-create.sql,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/sql/postgresql/metadata-create.sql 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/sql/postgresql/metadata-create.sql 15 Feb 2005 13:55:34 -0000 1.2 @@ -220,6 +220,9 @@ null, null ); + + insert into dtype_default_widgets (template_id, datatype) + values (v_template_id, ''email''); -- URL v_template_id := dtype_wdgt_tmpl__new ( @@ -233,6 +236,9 @@ null ); + insert into dtype_default_widgets (template_id, datatype) + values (v_template_id, ''url''); + -- Integer (default ''integer'' widget) v_template_id := dtype_wdgt_tmpl__new ( null, @@ -393,6 +399,18 @@ insert into dtype_default_widgets (template_id, datatype) values (v_template_id, ''enumeration''); + -- create ''default'' form for acs_object with only object_id so that + -- by default the dtype::form api doesn''t try to add acs_object + -- attributes to forms + PERFORM dtype_widget__register_form_widget( + ''acs_object'', + ''default'', + ''object_id'', + ''hidden'', + ''t'', + ''t'' + ); + return 0; end;' language 'plpgsql'; Index: openacs-4/packages/dynamic-types/tcl/form-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/form-procs.tcl,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/tcl/form-procs.tcl 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/tcl/form-procs.tcl 15 Feb 2005 13:55:34 -0000 1.2 @@ -4,7 +4,7 @@ The API manipulates two concepts - forms and widgets. Forms are mapped to object_types. Each object_type can have several named forms - mapped to it and is always mapped to a form called 'default'. Each + mapped to it and is always mapped to a form called 'implicit'. Each form is mapped to several widgets which correspond to the attributes of its object_type. @@ -13,7 +13,7 @@ modified by public users whereas the admin form could contain additional elements that admin users can edit. - The default form always contains widgets for all attributes in a type. + The implicit form always contains widgets for all attributes in a type. Widgets have associated parameters which control how the html representation is displayed, how values and options are retrieved and @@ -22,7 +22,7 @@ to play when a widget is combined a datatype - for example, the default options for a radio widget used for a boolean datatype are 'Yes' and 'No'. Any parameter can, and often should, be overridden - for non-default forms. + for non-implicit forms. } namespace eval dtype {} @@ -34,9 +34,10 @@ {-prefix ""} {-section ""} {-object_type ""} - {-dform default} - {-dforms {content_revision standard}} + {-dform implicit} + {-dforms {acs_object default content_revision default}} {-form:required} + {-overrides {}} {-cr_widget textarea} {-cr_widget_options {}} } { @@ -54,62 +55,76 @@ @param dform specifies the stored object form to use @param dforms specifies the stored object form to use for particular object types - used to override the dform parameter - @param form the name of the template::form to add the elements to + @param form the name of the template::form to add the elements to (will + create the form if it doesn't already exist) @param prefix prefix for each attribute name to avoid collisions @param section form section that the elements should be added to + @param overrides key value pairs that will override the initial value of + a form element irrespective of the default value in the form + metadata of the value in the object being edited @param content_widget the widget to use for the content when the object_type is a subtype of content_revision } { + if {![template::form exists $form]} { + template::form create $form + } + set types [dtype::form::types_list \ -object_id $object_id \ -object_type $object_type] set object_type [lindex $types 0] + set action edit + array set type_dforms $dforms + array set override $overrides - foreach type $types { - # Add form elements for all types except for acs_object - if {[string equal $type "acs_object"]} { - if {![string equal $object_id ""]} { - # object exists so preserve the object_id in the form - template::element create $form ${prefix}object_id \ - -widget hidden \ - -datatype text \ - -section $section \ - -value $object_id - } - } else { - if {[info exists type_dforms($type)]} { - set type_dform $type_dforms($type) - } else { - set type_dform $dform - } + if {![string equal $object_id ""] && + [info exists override(object_id)]} { + error "Cannot override object_id for an existing object" + } elseif {[string equal $object_id ""]} { + set action new - dtype::get_object -object_id $object_id \ - -object_type $object_type \ - -array object + if {![info exists override(object_id)]} { + set override(object_id) [db_nextval acs_object_id_seq] + } + } - # ensure the array exists - set object(object_id) $object_id + template::element create $form ${prefix}dform_action \ + -widget hidden \ + -datatype text \ + -sign \ + -value $action - dtype::form::add_type_elements -object_array object \ - -prefix $prefix \ - -section $section \ - -object_type $type \ - -dform $type_dform \ - -form $form \ - -cr_widget $cr_widget \ - -cr_widget_options $cr_widget_options + foreach type $types { + if {[info exists type_dforms($type)]} { + set type_dform $type_dforms($type) + } else { + set type_dform $dform } + + dtype::get_object -object_id $object_id \ + -object_type $object_type \ + -array object + set object(object_id) $object_id + + dtype::form::add_type_elements -object_array object \ + -prefix $prefix \ + -section $section \ + -object_type $type \ + -dform $type_dform \ + -form $form \ + -overrides [array get override] \ + -cr_widget $cr_widget \ + -cr_widget_options $cr_widget_options } } ad_proc -public dtype::form::process { - {-object_id ""} {-prefix ""} {-object_type ""} - {-dform default} - {-dforms {content_revision standard}} + {-dform implicit} + {-dforms {acs_object default content_revision default}} {-form:required} {-defaults {}} {-cr_widget textarea} @@ -128,18 +143,32 @@ types - used to override the dform parameter @param form the name of the template::form used @param prefix the prefix for each attribute name used - @param defaults default values to use for attributes + @param defaults default values to use for attributes (this should be used + to supply values for context_id and the like) @param cr_widget the input method for the content @param cr_storage the content repository storage method

TODO: Add support for HTMLArea.

@see dtype::form::add_elements } { - set types [dtype::form::types_list \ - -object_id $object_id \ - -object_type $object_type] - set new_p [string equal $object_id ""] + # Pull the object_id out of the form - technically a acs_object dform + # could be created that doesn't include object_id as a field in which + # case this would just break. + set object_id [template::element::get_value $form ${prefix}object_id] + + # Pull the action out of the form + set action [template::element::get_value $form ${prefix}dform_action] + set new_p [string equal $action "new"] + + if {$new_p} { + set types [dtype::form::types_list \ + -object_type $object_type] + } else { + set types [dtype::form::types_list \ + -object_id $object_id] + } + set content_type_p [expr {[lsearch $types "content_revision"] >= 0}] db_1row get_type_info {} -column_array type_info @@ -173,14 +202,14 @@ set item_id [db_nextval acs_object_id_seq] array set item_defaults [list item_id $item_id \ - name "item$item_id" \ - locale [db_null] \ - parent_id [db_null] \ - content_type $object_type \ - creation_user [ad_conn user_id] \ - creation_ip [ad_conn peeraddr] \ - storage_type $cr_storage] - + name "item$item_id" \ + locale [db_null] \ + parent_id [db_null] \ + content_type $object_type \ + creation_user [ad_conn user_id] \ + creation_ip [ad_conn peeraddr] \ + storage_type $cr_storage] + foreach var [array names item_defaults] { if {[info exists default($var)]} { set item_$var $default($var) @@ -234,85 +263,91 @@ set columns [list] set values [list] - # DAVEB since add_elements exlcudes acs_object attributes, we need - # to set some of them to resonable defaults + # DAVEB since add_elements excludes acs_object attributes, we need + # to set some of them to reasonable defaults # object_type # what do we do about context_id? Its application specific + # LEED context_id and similar fields should be passed in using the + # -defaults { context_id 1234 } argument foreach type $types { - # Add attributes to $columns and associated bind variables to $values - # for each type - if {[info exists type_dforms($type)]} { - set type_dform $type_dforms($type) - } else { - set type_dform $dform - } + # Add attributes to $columns and associated bind variables to $values + # for each type + if {[info exists type_dforms($type)]} { + set type_dform $type_dforms($type) + } else { + set type_dform $dform + } - # get the attribute metadata for the object type - dtype::get_attributes -name $type \ - -start_with $type \ - attributes + # get the attribute metadata for the object type + dtype::get_attributes -name $type \ + -start_with $type \ + attributes - dtype::form::metadata::widgets -object_type $type \ + dtype::form::metadata::widgets -object_type $type \ -dform $type_dform \ -indexed_array widgets - set size [template::multirow size attributes] - for {set i 1} {$i <= $size} {incr i} { - template::multirow get attributes $i + set size [template::multirow size attributes] + for {set i 1} {$i <= $size} {incr i} { + template::multirow get attributes $i - set crv_$attributes(name) "" + set crv_$attributes(name) "" - if {[info exists widgets($attributes(attribute_id))]} { +ns_log debug "PROCESSING: $attributes(name)" + if {[info exists widgets($attributes(attribute_id))]} { +ns_log debug "PROCESSING: found $attributes(name) in form" - # first check for the attribute in the submitted form - set crv_$attributes(name) [template::element::get_values \ - $form \ - ${prefix}$attributes(name)] + # first check for the attribute in the submitted form + set crv_$attributes(name) [template::element::get_values \ + $form \ + ${prefix}$attributes(name)] - } elseif {[info exists default($attributes(name))]} { + } elseif {[info exists default($attributes(name))]} { +ns_log debug "PROCESSING: using supplied default for $attributes(name)" - # second check if the caller supplied a default value - set crv_$attributes(name) $default($attributes(name)) + # second check if the caller supplied a default value + set crv_$attributes(name) $default($attributes(name)) - } elseif {$new_p && - ![string equal $attributes(default_value) ""]} { + } elseif {$new_p && + ![string equal $attributes(default_value) ""]} { +ns_log debug "PROCESSING: using attribute default for $attributes(name)" - # if we are inserting a new object then use the attributes - # default value - set crv_$attributes(name) $attributes(default_value) + # if we are inserting a new object then use the attributes + # default value + set crv_$attributes(name) $attributes(default_value) - } elseif {!$new_p} { + } elseif {!$new_p} { +ns_log debug "PROCESSING: using existing value for $attributes(name) (ie. adding it to missing columns)" - # append the column to missing columns so that the value - # is copied from the previous revision when we are dealing - # with content types - lappend missing_columns $attributes(column_name) + # append the column to missing columns so that the value + # is copied from the previous revision when we are dealing + # with content types + lappend missing_columns $attributes(column_name) - } + } - if {![string equal [set crv_$attributes(name)] ""]} { - lappend columns $attributes(column_name) + if {![string equal [set crv_$attributes(name)] ""]} { + lappend columns $attributes(column_name) - # cast the value to the appropriate datatype - switch $attributes(datatype) { - date - - time_of_day - - timestamp { - lappend values [template::util::date::get_property \ - sql_date \ - [lindex [set crv_$attributes(name)] 0]] - } - default { - lappend values ":crv_$attributes(name)" - } + # cast the value to the appropriate datatype + switch $attributes(datatype) { + date - + time_of_day - + timestamp { + lappend values [template::util::date::get_property \ + sql_date \ + [lindex [set crv_$attributes(name)] 0]] } + default { + lappend values ":crv_$attributes(name)" + } } } } + } - ####################################################### # Perform the insert or update as appropriate # @@ -388,12 +423,13 @@ {-prefix ""} {-section ""} {-object_type:required} - {-dform default} + {-dform implicit} {-form:required} + {-overrides {}} {-cr_widget textarea} {-cr_widget_options {}} } { - Adds the elements of the specified or default object form to the specified + Adds the elements of the specified or implicit object form to the specified template form. @param object_array the object for the form (not set for object creation) @@ -404,6 +440,7 @@ @param section optional form section that the elements should be added to } { upvar $object_array object + array set override $overrides set new_p [string equal $object(object_id) ""] @@ -444,16 +481,27 @@ append element_create_cmd " -optional" } - if {!$new_p && ![string equal $widgets(widget) file]} { - # Append the values in the object array - append element_create_cmd " [dtype::form::value_switch \ - -widget $widgets(widget) \ - -value $object($widgets(attribute_name))]" + if {![string equal $widgets(widget) file]} { + # Append the initial value + if {[info exists override($widgets(attribute_name))]} { + append element_create_cmd " [dtype::form::value_switch \ + -widget $widgets(widget) \ + -value $override($widgets(attribute_name))]" + } elseif {$new_p} { + append element_create_cmd " [dtype::form::value_switch \ + -widget $widgets(widget) \ + -value $widgets(default_value)]" + } else { + append element_create_cmd " [dtype::form::value_switch \ + -widget $widgets(widget) \ + -value $object($widgets(attribute_name))]" + } } # Get all the params for this element for {} {$p <= $param_count} {incr p} { template::multirow get params $p + if {$params(attribute_id) != $widgets(attribute_id)} { # No more parameters for this widget, finish # processing this element @@ -495,6 +543,11 @@ append options_line " -${name} \$overridables($name)" } + # sign all hidden variables + if {[string equal $widgets(widget) "hidden"]} { + append options_line " -sign" + } + # Actually create the element eval "$element_create_cmd $options_line" } @@ -526,12 +579,22 @@ append element_create_cmd " -optional" } - if {!$new_p && ![string equal $cr_widget file]} { - # Append the content value - append element_create_cmd " [dtype::form::value_switch \ - -widget $cr_widget \ - -value [cr_write_content -string \ - -revision_id $object(object_id)]]" + if {![string equal $cr_widget file]} { + if {[info exists override($widgets(attribute_name))]} { + append element_create_cmd " [dtype::form::value_switch \ + -widget $widgets(widget) \ + -value $override($widgets(attribute_name))]" + } elseif {!$new_p} { + append element_create_cmd " [dtype::form::value_switch \ + -widget $widgets(widget) \ + -value $widgets(default_value)]" + } else { + # Append the content value + append element_create_cmd " [dtype::form::value_switch \ + -widget $cr_widget \ + -value [cr_write_content -string \ + -revision_id $object(object_id)]]" + } } # Actually create the element @@ -720,7 +783,7 @@ -dform $dform] ns_log notice " - DB -------------------------------------------------------------------------------- +DB -------------------------------------------------------------------------------- DB DAVE debugging procedure dtype::form::metadata::widgets DB -------------------------------------------------------------------------------- DB object_type = '${object_type}'