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 -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql 15 Feb 2005 13:55:34 -0000 1.1 +++ openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql 24 Feb 2005 14:21:50 -0000 1.2 @@ -418,17 +418,9 @@ 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; - + select content_type__is_content_type(p_object_type) + into v_content_revision_p; + -- -- start building rule code -- @@ -576,7 +568,6 @@ 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, @@ -590,7 +581,6 @@ -- 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, 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 -r1.2 -r1.3 --- openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql 15 Feb 2005 13:55:34 -0000 1.2 +++ openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql 24 Feb 2005 14:21:50 -0000 1.3 @@ -442,7 +442,9 @@ and object_type = p_object_type; if NOT FOUND then - raise EXCEPTION ''-20000: Attribute %: % does not exist in dtype_widget.register_form_widget'', p_object_type, p_attribute_name; + if p_object_type <> ''acs_object'' and p_attribute_name <> ''object_id'' then + raise EXCEPTION ''-20000: Attribute %: % does not exist in dtype_widget.register_form_widget'', p_object_type, p_attribute_name; + end if; end if; -- Look for the form Index: openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl,v diff -u -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl 24 Feb 2005 14:21:50 -0000 1.2 @@ -28,28 +28,25 @@ } { upvar $array local - dtype::get_attributes -name $object_type attributes - db_1row select_table_name {} + set attributes_list [dtype::get_attributes -name $object_type -list t attributes] set columns [list] - set size [template::multirow size attributes] - for {set i 1} {$i <= $size} {incr i} { - template::multirow get attributes $i - - switch $attributes(datatype) { + foreach attribute_info $attributes_list { + foreach {name pretty_name attribute_id datatype table_name column_name default_value min_n_values max_n_values static_p} $attribute_info break + switch $datatype { date - timestamp - time_of_day { set format "'YYYY-MM-DD HH24:MI:SS'" - lappend columns "to_char($attributes(column_name), $format) as $attributes(name)" + lappend columns "to_char($column_name, $format) as $name" } default { - lappend columns "$attributes(column_name) as $attributes(name)" + lappend columns "$column_name as $name" } } } - + db_1row select_table_name {} set columns [join $columns ", "] db_0or1row select_object {} -column_array local } @@ -113,7 +110,9 @@ set default_value [db_null] } - db_1row select_column_spec {} + if {![db_0or1row select_column_spec {}]} { + set column_spec "" + } db_exec_plsql create_attr {} @@ -127,43 +126,50 @@ {-name:required} {-start_with "acs_object"} {-storage_types "type_specific"} + {-list "f"} multirow } { Gets all the attributes of a object_type. Optionally it can return only those attributes after a given name. } { - template::multirow create $multirow \ - name \ - pretty_name \ - attribute_id \ - datatype \ - table_name \ - column_name \ - default_value \ - min_n_values \ - max_n_values \ - storage \ - static_p set attributes [dtype::get_attributes_list \ -name $name \ -start_with $start_with \ -storage_types $storage_types] - foreach attribute $attributes { - template::multirow append $multirow \ - [lindex $attribute 0] \ - [lindex $attribute 1] \ - [lindex $attribute 2] \ - [lindex $attribute 3] \ - [lindex $attribute 4] \ - [lindex $attribute 5] \ - [lindex $attribute 6] \ - [lindex $attribute 7] \ - [lindex $attribute 8] \ - [lindex $attribute 9] \ - [lindex $attribute 10] - } + if {!$list} { + + template::multirow create $multirow \ + name \ + pretty_name \ + attribute_id \ + datatype \ + table_name \ + column_name \ + default_value \ + min_n_values \ + max_n_values \ + storage \ + static_p + + foreach attribute $attributes { + template::multirow append $multirow \ + [lindex $attribute 0] \ + [lindex $attribute 1] \ + [lindex $attribute 2] \ + [lindex $attribute 3] \ + [lindex $attribute 4] \ + [lindex $attribute 5] \ + [lindex $attribute 6] \ + [lindex $attribute 7] \ + [lindex $attribute 8] \ + [lindex $attribute 9] \ + [lindex $attribute 10] + } + } else { + return $attributes + } } ad_proc -private dtype::get_attributes_list { @@ -239,6 +245,7 @@ util::event::fire -event dtype.attribute event } + ad_proc -public dtype::def_from_table { {-supertype "acs_object"} {-table_name:required} @@ -280,23 +287,183 @@ " # get columns from table - set cols [dtype::table::get_table_array -table $table_name] + array set cols [dtype::table::get_table_array -table $table_name] + set fks [dtype::table::get_fk -table $table_name] + foreach l $fks { + foreach {col fk_col fk_table object_p} $l break + # if columns has a foreign key and its not referrign to an + # acs_object, its probably a lookup table + if {!$object_p} { + set cols($col) "enumeration" + } + } set type_map [dtype::table::get_db_type_map] - foreach {col type} $cols { +ns_log notice " +DB -------------------------------------------------------------------------------- +DB DAVE debugging procedure dtype::def_from_table +DB -------------------------------------------------------------------------------- +DB fks = '${fks}' +DB [array names cols] +DB --------------------------------------------------------------------------------" + foreach col [array names cols] { + set type $cols($col) # append create attribute code if {$col != $id_column} { - append code " - dtype::create_attribute \ - -name \"${col}\" \ - -object_type \"${name}\" \ - -data_type \"[string map $type_map $type]\" \ - -pretty_name \"[dtype::table::pretty_name $col]\" \ - -pretty_plural \"[dtype::table::pretty_plural $col]\" \ - -sort_order \"\" \ - -default_value \"\" + # if foreign key and foreign key is not an object + append code " +dtype::create_attribute \ + -name \"${col}\" \ + -object_type \"${name}\" \ + -data_type \"[string map $type_map $type]\" \ + -pretty_name \"[dtype::table::pretty_name $col]\" \ + -pretty_plural \"[dtype::table::pretty_plural $col]\" \ + -sort_order \"\" \ + -default_value \"\" " + } } - } + return $code } +ad_proc -public dtype::create_form { + -object_type + {-dform "standard"} + {-dforms {content_revision standard acs_object empty_acs_object}} + {-exclude ""} + {-spec ""} + {-evaluate "t"} +} { + Create a dynamic types form for object type based on type + definition using intelligent defaults. + + @author Dave Bauer (dave@thedesignexperience.org) + @creation-date 2005-02-14 + + @param object_type Object type form is for + + @param dform Name of form. We can't use 'default' because that is + reserved for the unspecificed form. + + @param exclude Attributes to exclude from automatically generated form. + + @param spec Declarative specification for form defintion. Optional + instead of calling dtype::form::generate_widget repeatedly + + @param evaluate T or F, whether to evalute the code or just + return it + + @return If evaluate is false, return code generated. + + @error +} { + set code "" + # get widget defaults + + # get all types + set types [dtype::form::types_list \ + -object_id "" \ + -object_type $object_type] + set object_type [lindex $types 0] + + array set type_dforms $dforms + + # FIXME use spec if available! + + # get default widgets + foreach type $types { + if {[info exists type_dforms($type)]} { + set type_dform $type_dforms($type) + } else { + set type_dform "implicit" + } + + dtype::form::metadata::widgets -object_type $type \ + -dform $type_dform \ + -multirow widgets + set fks [dtype::table::get_fk -table [dtype::get_table_name -object_type $type]] + foreach l $fks { + set fk_array([lindex $l 0]) [lrange $l 1 end] + } + template::multirow foreach widgets { + append code " + dtype::form::metadata::create_widget \ + -object_type $object_type \ + -dform $dform \ + -attribute_name $attribute_name \ + -widget $widget \ + -required_p 0 \ + -create_form_p 1 +" + # check attribute datatype + # for foreign keys, if should be enumeration + # if so, we want to create a select widget + # that queries the fk table + if {$datatype == "enumeration" && [info exists fk_array($attribute_name)]} { + set object_p [lindex $fk_array($attribute_name) 2] + if {!$object_p} { + # create widget param for select list + # if type of the foreign key table is a subtype of + # content revision, use the i view + # also check if its a dtype + + append code " + dtype::form::metadata::create_widget_param \ + -object_type $object_type \ + -dform $dform \ + -attribute_name $attribute_name \ + -param_name options \ + -type multilist \ + -source query \ + -value \"select title, [lindex $fk_array($attribute_name) 0] from [lindex $fk_array($attribute_name) 1]\" + " + } + + } + + + } + } + if {$evaluate} { + eval $code + } else { + return $code + } +} + +ad_proc -public dtype::get_table_name { + -object_type +} { + + Get name of type specicifc storage table + + @author Dave Bauer (dave@thedesignexperience.org) + @creation-date 2005-02-14 + + @param object_type Object type + + @return Table Name + + @error +} { + return [db_string get_table_name "" -default ""] +} + +ad_proc -public dtype::get_id_column { + -object_type +} { + + Get name of type specicifc storage table + + @author Dave Bauer (dave@thedesignexperience.org) + @creation-date 2005-02-14 + + @param object_type Object type + + @return Table Name + + @error +} { + return [db_string get_id_column "" -default ""] +} + Index: openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql,v diff -u -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql 24 Feb 2005 14:21:50 -0000 1.2 @@ -52,5 +52,19 @@ - + + + + select table_name from acs_object_types where + object_type=:object_type + + + + + + select id_column from acs_object_types where + object_type=:object_type + + + 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 -r1.3 -r1.4 --- openacs-4/packages/dynamic-types/tcl/form-procs.tcl 18 Feb 2005 17:54:18 -0000 1.3 +++ openacs-4/packages/dynamic-types/tcl/form-procs.tcl 24 Feb 2005 14:21:50 -0000 1.4 @@ -1,3 +1,4 @@ + ad_library { A library of functions to generate forms for acs_objects from stored metadata. @@ -89,7 +90,7 @@ set override(object_id) [db_nextval acs_object_id_seq] } } - + template::element create $form ${prefix}dform_action \ -widget hidden \ -datatype text \ @@ -134,9 +135,6 @@ Process a dynamic type form submission created by a function such as dtype::form::add_elements. - @param object_id the object represented in the form. If set the form is - assumed to be an edit form, otherwise it is assumed to be an object - create form @param object_type the object type whose metadata will define the form @param dform specifies the stored object form used @param dforms specifies the stored object form to use for particular object @@ -263,15 +261,11 @@ set columns [list] set values [list] - # 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 { - + set missing_columns "" # Add attributes to $columns and associated bind variables to $values # for each type if {[info exists type_dforms($type)]} { @@ -280,6 +274,13 @@ 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 \ @@ -298,15 +299,27 @@ 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 \ + array set this_widget_info $widgets($attributes(attribute_id)) + switch $this_widget_info(widget) { + file {} + checkbox - + multiselect { + set crv_$attributes(name) [template::element::get_values \ + $form \ + ${prefix}$attributes(name)] + } + default { + set crv_$attributes(name) [template::element::get_value \ $form \ ${prefix}$attributes(name)] - + } + } } elseif {[info exists default($attributes(name))]} { ns_log debug "PROCESSING: using supplied default for $attributes(name)" + if {![string equal [set crv_$attributes(name)] ""]} { + # second check if the caller supplied a default value set crv_$attributes(name) $default($attributes(name)) @@ -327,7 +340,6 @@ lappend missing_columns $attributes(column_name) } - if {![string equal [set crv_$attributes(name)] ""]} { lappend columns $attributes(column_name) @@ -356,17 +368,17 @@ if {$new_p} { db_dml insert_statement " insert into ${type_info(table_name)}i - (item_id, [join $columns ", "]) + ([join [concat "item_id" "revision_id" $columns] ", "]) values - (:item_id, [join $values ", "])" + ([join [concat ":item_id" ":object_id" $values] ", "])" } else { set latest_revision [content::item::get_latest_revision -item_id $item_id] db_dml insert_statement " insert into ${type_info(table_name)}i - (item_id, [join [concat $columns $missing_columns] ", "]) - select item_id, - [join [concat $values $missing_columns] ", "] + ([join [concat "item_id" "revision_id" $columns $missing_columns] ", "]) + select + [join [concat ":item_id" ":object_id" $values $missing_columns] ", "] from ${type_info(table_name)}i where revision_id = $latest_revision" } @@ -480,10 +492,10 @@ if {![template::util::is_true $widgets(is_required)]} { append element_create_cmd " -optional" } - + if {![string equal $widgets(widget) file]} { # Append the initial value - if {[info exists override($widgets(attribute_name))]} { + if {[info exists override(${widgets(attribute_name)})]} { append element_create_cmd " [dtype::form::value_switch \ -widget $widgets(widget) \ -value $override($widgets(attribute_name))]" @@ -584,7 +596,8 @@ append element_create_cmd " [dtype::form::value_switch \ -widget $widgets(widget) \ -value $override($widgets(attribute_name))]" - } elseif {!$new_p} { + } elseif {$new_p} { + # don't try to put content in the form element on new form append element_create_cmd " [dtype::form::value_switch \ -widget $widgets(widget) \ -value $widgets(default_value)]" @@ -612,13 +625,13 @@ file {} checkbox - multiselect { - return "-values $value" + return "-values \"$value\"" } date { return "-value {[template::util::date::from_ansi $value]}" } default { - return "-value $value" + return "-value \"$value\"" } } } @@ -693,7 +706,6 @@ if {[string equal $object_type ""]} { set object_type [db_string get_object_type {}] } - switch $param(param_source) { eval { set value [eval $param(value)] @@ -709,6 +721,11 @@ } multilist { set value [db_list_of_lists param_query $param(value)] + # if the option list is empty, return + # somethign the select widget can use + if {$value eq ""} { + set value [list [list]] + } } } }] { @@ -725,7 +742,6 @@ } } # end switch - return $value } @@ -781,14 +797,6 @@ set metadata [dtype::form::metadata::widgets_list \ -object_type $object_type \ -dform $dform] -ns_log notice " - -DB -------------------------------------------------------------------------------- -DB DAVE debugging procedure dtype::form::metadata::widgets -DB -------------------------------------------------------------------------------- -DB object_type = '${object_type}' -DB metadata = '${metadata}' -DB --------------------------------------------------------------------------------" foreach widget $metadata { if {$multirow_p} { eval "template::multirow append \$multirow $widget" Index: openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql,v diff -u -r1.1 -r1.2 --- openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql 14 Feb 2005 14:33:28 -0000 1.1 +++ openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql 24 Feb 2005 14:21:50 -0000 1.2 @@ -15,12 +15,15 @@ - int4 integer varchar string boolean boolean numeric number real - number float number integer integer serial integer money money - date date timestamp timestamp timestamptz timestamp "timestamp - with time zone" timestamp "timestamp without time zone" - timestamp time time_of_day "time without time zone" time_of_day - "time with time zone" time_of_day "" enumeration "" url "" email text text "" keyword + int4 integer varchar text boolean boolean numeric + number real number float number integer integer serial integer + money money date date timestamptz date + "timestamp with time zone" date + "timestamp without time zone" date + timestamp date + "time without time zone" time_of_day + "time with time zone" time_of_day time time_of_day "" enumeration + "" url "" email "" keyword @@ -74,4 +77,30 @@ and t.table_name=st.relname + + + + select pa1.attname, + pa2.attname, + pc2.relname, + case when ot.object_type is null then 0 else 1 end + as object_p + from pg_attribute pa1, + pg_attribute pa2, + pg_constraint, + pg_class pc1, + pg_class pc2 + left join + acs_object_types ot + on pc2.relname=ot.table_name + where conrelid=pc1.oid + and pc1.relname=:table + and contype='f' + and confrelid=pc2.oid + and pa2.attnum = any(pg_constraint.confkey) + and pa2.attrelid=pc2.oid + and pc1.oid=pa1.attrelid + and pa1.attnum=any(pg_constraint.conkey); + +