- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::xo::db::CrClass
::xo::db::CrClass create ... \
[ -edit_form edit_form ] \
[ -folder_id (default "-100") ] \
[ -form form ] \
[ -mime_type (default "text/plain") ] \
[ -non_cached_instance_var_patterns (default "__*") ] \
[ -storage_type (default "text") ] \
[ -supertype (default "content_revision") ]
Defined in
Class Relations
- class: ::xotcl::Class
- superclass: ::xo::db::Class
- instmixin: ::xo::db::CrCache
- mixin: ::xo::db::CrCache::Class
::xotcl::Class create ::xo::db::CrClass \ -superclass ::xo::db::Class \ -instmixin ::xo::db::CrCache \ -mixin ::xo::db::CrCache::ClassMethods (to be applied on the object)
delete (scripted, public)
xo::db::CrClass delete [ -item_id item_id ]Delete a CrItem in the database
- Switches:
- -item_id (optional)
- Testcases:
- xotcl_core_tutorial_4
set object_type [:get_object_type -item_id $item_id] $object_type delete -item_id $item_idensure_item_ids_instantiated (scripted, public)
xo::db::CrClass ensure_item_ids_instantiated [ -initialize on|off ] \ -item_ids item_idsMake sure, the objects all of the provided items_ids are instantiated (i.e. the same-named objects do exist as executable commands in the current thread).
- Switches:
- -initialize (optional, boolean, defaults to
"true"
)- -item_ids (required)
- Testcases:
- link_tests
foreach item_id $item_ids { #if {![::nsf::is object ::$item_id]} { ns_log notice "===== we have to fetch ::$item_id"} :get_instance_from_db -item_id $item_id -initialize $initialize }get_child_item_ids (scripted, public)
xo::db::CrClass get_child_item_ids -item_id item_idReturn a list of content items having the provided item_id as direct or indirect parent. The method returns recursively all item_ids.
- Switches:
- -item_id (required)
- Returns:
- list of item_ids
- Testcases:
- xowiki_test_cases
# # The following construct (commented out) is fully PostgreSQL and # Oracle compliant. However, all newer Oracle installations # should as well support the recursive query below as well, which # requires less DB interactions. # # set items [list] # foreach item_id [::xo::dc list -prepare integer get_child_items # "select item_id from cr_items where parent_id = :item_id"] { # lappend items $item_id {*}[my [self proc] -item_id $item_id] # } # return $items return [::xo::dc list -prepare integer get_child_items { WITH RECURSIVE child_items AS ( select item_id from cr_items where parent_id = :item_id UNION ALL select i.item_id from cr_items i, child_items where i.parent_id = child_items.item_id ) select * from child_items }]get_instance_from_db (scripted, public)
xo::db::CrClass get_instance_from_db [ -item_id item_id ] \ [ -revision_id revision_id ] [ -initialize on|off ]Instantiate the live revision or the specified revision of an CrItem. The XOTcl object is destroyed automatically on cleanup (end of a connection request).
- Switches:
- -item_id (optional, integer, defaults to
"0"
)- -revision_id (optional, integer, defaults to
"0"
)- -initialize (optional, boolean, defaults to
"true"
)- Returns:
- fully qualified object containing the attributes of the CrItem
- Testcases:
- test_cr_items, create_workflow_with_instance, xowiki_test_cases, link_tests, slot_interactions, path_resolve
set object ::[expr {$revision_id ? $revision_id : $item_id}] if {$object eq "::0"} { set msg "get_instance_from_db must be called with either item_id or revision_id different from 0" ad_log error $msg error $msg } if {![::nsf::is object $object]} { set object_type [:get_object_type -item_id $item_id -revision_id $revision_id] set class [::xo::db::Class object_type_to_class $object_type] set object [$class get_instance_from_db -item_id $item_id -revision_id $revision_id -initialize $initialize] } return $objectget_name (scripted, public)
xo::db::CrClass get_name -item_id item_idGet the name of a content item either from an already instantiated object or from the database without instantiating it. If item_id is not a valid item_id, we throw an error.
- Switches:
- -item_id (required)
- Returns:
- parent_id
- Testcases:
- xowiki_test_cases
# TODO: the following line is deactivated, until we get rid of the "folder object" in xowiki #if {[nsf::is object ::$item_id]} {return [::$item_id parent_id]} ::xo::dc 1row -prepare integer get_name "select name from cr_items where item_id = :item_id" return $nameget_object_type (scripted, public)
xo::db::CrClass get_object_type -item_id item_id \ [ -revision_id revision_id ]Return the object type for an item_id or revision_id.
- Switches:
- -item_id (required, integer)
- -revision_id (optional, integer, defaults to
"0"
)- Returns:
- object_type typically an XOTcl class
- Testcases:
- test_xo_db_object, test_cr_items
# # Use a request-spanning cache. When the object_type would change, # we require xo::broadcast or server restart. # set key ::xo::object_type($item_id,$revision_id) if {[info exists $key]} { return [set $key] } set entry_key [expr {$item_id ? $item_id : $revision_id}] set $key [xo::xotcl_object_type_cache eval -partition_key $entry_key $entry_key { if {$item_id} { ::xo::dc 1row -prepare integer get_class_from_item_id "select content_type as object_type from cr_items where item_id=:item_id" } else { ::xo::dc 1row -prepare integer get_class_from_revision_id "select object_type from acs_objects where object_id=:revision_id" } return $object_type }]get_parent_id (scripted, public)
xo::db::CrClass get_parent_id -item_id item_idGet the parent_id of a content item either from an already instantiated object or from the database without instantiating it. If item_id is not a valid item_id, we throw an error.
- Switches:
- -item_id (required)
- Returns:
- parent_id
- Testcases:
- xowiki_test_cases
# TODO: the following line is deactivated, until we get rid of the "folder object" in xowiki #if {[nsf::is object ::$item_id]} {return [::$item_id parent_id]} ::xo::dc 1row -prepare integer get_parent "select parent_id from cr_items where item_id = :item_id" return $parent_idid_belongs_to_package (scripted, public)
xo::db::CrClass id_belongs_to_package [ -item_id item_id ] \ [ -revision_id revision_id ] -package_id package_idCheck if the provided item_id or revision_id belongs to the provided package.
- Switches:
- -item_id (optional, integer, defaults to
"0"
)- -revision_id (optional, integer, defaults to
"0"
)- -package_id (required, integer)
- Returns:
- boolean success
- Testcases:
- create_form_with_form_instance, check_page_template_constraint
set id [expr {$revision_id ? $revision_id : $item_id}] if {$id eq 0} { return 0 } set what [expr {$item_id != 0 ? "item_id" : "revision_id"}] return [::xo::dc 0or1row -prepare integer,integer check_package [subst { select 1 from cr_items, acs_objects where $what = :$what and object_id = :$what and package_id = :package_id fetch first 1 rows only }]]lookup (scripted, public)
xo::db::CrClass lookup -name name [ -parent_id parent_id ] \ [ -content_type content_type ]Check, whether a content item with the given name exists. When content_type is provided (e.g. -content_type "::%") then a like operation is applied on the value.
- Switches:
- -name (required)
- -parent_id (optional, defaults to
"-100"
)- -content_type (optional)
- Returns:
- item_id If the item exists, return its item_id, otherwise 0.
- Testcases:
- xotcl_core_tutorial_4, create_folder_with_page, xowiki_test_cases, path_resolve
if {[info exists content_type]} { set result [::xo::dc get_value lookup_by_name_and_ct { select item_id from cr_items where name = :name and parent_id = :parent_id and content_type like :content_type } 0] } else { set result [::xo::dc get_value lookup_by_name { select item_id from cr_items where name = :name and parent_id = :parent_id } 0] } return $resultMethods (to be applied on instances)
create_object_type (scripted, public)
<instance of xo::db::CrClass> create_object_typeCreate an oacs object_type and a table for keeping the additional attributes.
- Testcases:
- xotcl_core_tutorial_4
:check_table_atts set :supertype [:info superclass] switch -- ${:supertype} { ::xotcl::Object - ::xo::db::CrItem {set :supertype content_revision} } if {![info exists :pretty_plural]} {set :pretty_plural ${:pretty_name}} ::xo::dc transaction { ::acs::dc call content_type create_type -content_type ${:object_type} -supertype ${:supertype} -pretty_name ${:pretty_name} -pretty_plural ${:pretty_plural} -table_name ${:table_name} -id_column ${:id_column} -name_method ${:name_method} :folder_type register }delete (scripted, public)
<instance of xo::db::CrClass> delete -item_id item_idDelete a content item from the content repository.
- Switches:
- -item_id (required)
- id of the item to be deleted
- Testcases:
- xotcl_core_tutorial_4, xowiki_test_cases
::acs::dc call content_item del -item_id $item_iddrop_object_type (scripted, public)
<instance of xo::db::CrClass> drop_object_typeDelete the object type and remove the table for the attributes. This method should be called when all instances are deleted. It undoes everying what create_object_type has produced.
- Testcases:
- xotcl_core_tutorial_4
set object_type ${:object_type} ::xo::dc transaction { :folder_type unregister ::acs::dc call content_type drop_type -content_type ${:object_type} -drop_children_p t -drop_table_p t }edit_atts (scripted)
# TODO remove, when name and text are slots (only for generic) array names :db_slotedit_form (setter)
fetch_object (scripted, public)
<instance of xo::db::CrClass> fetch_object -item_id item_id \ [ -revision_id revision_id ] -object object \ [ -initialize on|off ]Load a content item into the specified object. If revision_id is provided, the specified revision is returned, otherwise the live revision of the item_id. If the object does not exist, we create it.
- Switches:
- -item_id (required)
- -revision_id (optional, defaults to
"0"
)- -object (required)
- -initialize (optional, boolean, defaults to
"true"
)- Returns:
- cr item object
- Testcases:
- xotcl_core_tutorial_4, xowiki_test_cases
# :log "-- generic fetch_object [self args]" if {![nsf::is object $object]} { # if the object does not yet exist, we have to create it :create $object } set raw_atts [::xo::db::CrClass set common_query_atts] #:log "-- raw_atts = '$raw_atts'" set atts [list] foreach v $raw_atts { switch -glob -- $v { publish_status {set fq i.$v} storage_type {set fq i.$v} creation_date {set fq o.$v} creation_user {set fq o.$v} package_id {set fq o.$v} default {set fq n.$v} } lappend atts $fq } foreach {slot_name slot} [array get :db_slot] { switch -glob -- $slot { ::xo::db::CrItem::slot::text { # # We need the rule, since insert the handling of the sql # attribute "text" is somewhat magic. On insert, one can use # the automatic view with column_name "text, on queries, one # has to use "data". Therefore, we cannot use simply # -column_name for the slot. # lappend atts "n.data AS text" } ::xowiki::Page::slot::text { # # This is just a hotfix for now. # #ns_log notice [$slot serialize] lappend atts "n.data as text" } ::xo::db::CrItem::slot::name { lappend atts i.[$slot column_name] } ::xo::db::Object::slot::context_id { # # If we are fetching by revision_id, skip the context_id, # since on object-save-operations, we want to keep the # context_id of the item, and not the context_id from the # revision. # if {$revision_id == 0} { # # Fetch by item_id. # lappend atts o.[$slot column_name] } } ::xo::db::Object::slot::* { lappend atts o.[$slot column_name] } default { lappend atts n.[$slot column_name] } } } if {$revision_id} { $object set revision_id $revision_id set sql [subst { select [join $atts ,], i.parent_id from ${:table_name}i n, cr_items i, acs_objects o where n.revision_id = :revision_id and i.item_id = n.item_id and o.object_id = n.revision_id }] set selection [lindex [::xo::dc sets -prepare integer fetch_object_from_revision_id $sql] 0] $object mset [ns_set array $selection] } else { # # We fetch the creation_user and the modifying_user by returning # the creation_user of the automatic view as modifying_user. In # case of troubles, comment next line out. # lappend atts "n.creation_user as modifying_user" $object set item_id $item_id $object db_1row [:qn fetch_from_view_item_id] " select [join $atts ,], i.parent_id from ${:table_name}i n, cr_items i, acs_objects o where i.item_id = :item_id and n.${:id_column} = coalesce(i.live_revision, i.latest_revision) and o.object_id = i.item_id" } # # The method "db_1row" treats all newly created variables as # instance variables, so we can see vars like "__db_sql", # "__db_lst" that we do not want to keep. # foreach v [$object info vars __db_*] { $object unset $v } # # Deactivate compatibility with versions before OpenACS 5.2 # (2005), since this is a busy code, but leave it here for easy # reactivating in legacy applications. # #if {[apm_version_names_compare [ad_acs_version] 5.2] <= -1} { # set parent_id [$object set parent_id] # $object set package_id [::xo::dc get_value get_pid { # select package_id from cr_folders where folder_id = :parent_id # } #} # :log "--AFTER FETCH\n[$object serialize]" if {$initialize} {$object initialize_loaded_object} return $objectfolder_id (setter)
folder_type (scripted, public)
<instance of xo::db::CrClass> folder_type \ [ -include_subtypes include_subtypes ] [ -folder_id folder_id ] \ operationregister the current object type for folder_id. If folder_id is not specified, use the instvar of the class instead.
- Switches:
- -include_subtypes (optional, defaults to
"t"
)- Boolean value (t/f) to flag whether the operation should be applied on subtypes as well
- -folder_id (optional)
- Parameters:
- operation (required)
- Testcases:
- xotcl_core_tutorial_4
if {$operation ne "register" && $operation ne "unregister"} { error "[self] operation for folder_type must be 'register' or 'unregister'" } if {![info exists folder_id]} { set folder_id ${:folder_id} } ::acs::dc call content_folder ${operation}_content_type -folder_id $folder_id -content_type ${:object_type} -include_subtypes $include_subtypesfolder_type_unregister_all (scripted, public)
<instance of xo::db::CrClass> folder_type_unregister_all \ [ -include_subtypes include_subtypes ]Unregister the object type from all folders on the system
- Switches:
- -include_subtypes (optional, defaults to
"t"
)- Boolean value (t/f) to flag whether the operation should be applied on subtypes as well
- Testcases:
- No testcase defined.
set object_type ${:object_type} xo::dc foreach all_folders { select folder_id from cr_folder_type_map where content_type = :object_type } { ::acs::dc call content_folder unregister_content_type -folder_id $folder_id -content_type $object_type -include_subtypes $include_subtypes }form (setter)
getFormClass (scripted)
if {[$data exists item_id] && [$data set item_id] != 0 && [info exists :edit_form]} { return [:edit_form] } else { return [:form] }get_instance_from_db (scripted, public)
<instance of xo::db::CrClass> get_instance_from_db \ [ -item_id item_id ] [ -revision_id revision_id ] \ [ -initialize on|off ]Retrieve either the live revision or a specified revision of a content item with all attributes into a newly created object. The retrieved attributes are stored in the instance variables in class representing the object_type. The XOTcl object is destroyed automatically on cleanup (end of a connection request)
- Switches:
- -item_id (optional, defaults to
"0"
)- id of the item to be retrieved.
- -revision_id (optional, defaults to
"0"
)- revision-id of the item to be retrieved.
- -initialize (optional, boolean, defaults to
"true"
)- Returns:
- fully qualified object
- Testcases:
- xotcl_core_tutorial_4, test_cr_items, create_folder_with_page, xowiki_test_cases, create_form_with_form_instance
set object ::[expr {$revision_id ? $revision_id : $item_id}] if {![nsf::is object $object]} { :fetch_object -object $object -item_id $item_id -revision_id $revision_id -initialize $initialize $object destroy_on_cleanup } return $objectget_instances_from_db (scripted, public)
<instance of xo::db::CrClass> get_instances_from_db \ [ -select_attributes select_attributes ] \ [ -from_clause from_clause ] [ -where_clause where_clause ] \ [ -orderby orderby ] [ -with_subtypes on|off ] \ [ -folder_id folder_id ] [ -page_size page_size ] \ [ -page_number page_number ] [ -base_table base_table ] \ [ -initialize initialize ]Returns a set (ordered composite) of the answer tuples of an 'instance_select_query' with the same attributes. The tuples are instances of the class, on which the method was called.
- Switches:
- -select_attributes (optional)
- -from_clause (optional)
- -where_clause (optional)
- -orderby (optional)
- -with_subtypes (optional, boolean, defaults to
"true"
)- -folder_id (optional)
- -page_size (optional, defaults to
"20"
)- -page_number (optional)
- -base_table (optional, defaults to
"cr_revisions"
)- -initialize (optional, defaults to
"true"
)- Testcases:
- xotcl_core_tutorial_4, create_form_with_form_instance
if {![info exists folder_id]} { set folder_id ${:folder_id} } set s [:instantiate_objects -sql [:instance_select_query -select_attributes $select_attributes -from_clause $from_clause -where_clause $where_clause -orderby $orderby -with_subtypes $with_subtypes -folder_id $folder_id -page_size $page_size -page_number $page_number -base_table $base_table ] -initialize $initialize] return $sinit (scripted)
# # First, do whatever ::xo::db::Class does for initialization ... # next # # We want to be able to define for different CrClasses different # default mime-types. Therefore, we define attribute slots per # application class with the given default for mime_type. # if {[self] ne "::xo::db::CrItem"} { :slots { ::xotcl::Attribute create mime_type -default [:mime_type] } :db_slots } # ... then we do the CrClass specific initialization. #if {[:info superclass] ne "::xo::db::CrItem"} { # set :superclass [[:info superclass] set object_type] #} # "CrClasses" stores all attributes of the class hierarchy in # db_slot. This is due to the usage of the # automatically created views. Note that classes created with # ::xo::db::Class keep only the class specific db slots. # foreach {slot_name slot} [[:info superclass] array get :db_slot] { # don't overwrite slots, unless the object_title (named title) if {![info exists :db_slot($slot_name)] || $slot eq "::xo::db::Object::slot::object_title"} { set :db_slot($slot_name) $slot } } :remember_long_text_slots if {![::xo::db::Class object_type_exists_in_db -object_type ${:object_type}]} { :create_object_type }insert_statement (scripted)
return "insert into ${:table_name}i ([join $atts ,]) values (:[join $vars ,:])"instance_select_query (scripted, public)
<instance of xo::db::CrClass> instance_select_query \ [ -select_attributes select_attributes ] [ -orderby orderby ] \ [ -where_clause where_clause ] [ -from_clause from_clause ] \ [ -with_subtypes on|off ] [ -with_children on|off ] \ [ -publish_status publish_status ] [ -count on|off ] \ [ -folder_id folder_id ] [ -parent_id parent_id ] \ [ -page_size page_size ] [ -page_number page_number ] \ [ -base_table base_table ]returns the SQL-query to select the CrItems of the specified object_type
- Switches:
- -select_attributes (optional)
- attributes for the SQL query to be retrieved, in addition to item_id, name, publish_status, object_type, and package_id which are always returned
- -orderby (optional)
- for ordering the solution set
- -where_clause (optional)
- clause for restricting the answer set
- -from_clause (optional)
- -with_subtypes (optional, boolean, defaults to
"true"
)- return subtypes as well
- -with_children (optional, boolean, defaults to
"false"
)- return immediate child objects of all objects as well
- -publish_status (optional)
- one of 'live', 'ready', or 'production'
- -count (optional, boolean, defaults to
"false"
)- return the query for counting the solutions
- -folder_id (optional)
- parent_id
- -parent_id (optional)
- -page_size (optional, defaults to
"20"
)- -page_number (optional)
- -base_table (optional, defaults to
"cr_revisions"
)- typically automatic view, must contain title and revision_id
- Returns:
- SQL query
- Testcases:
- xowiki_test_cases
if {![info exists folder_id]} {set folder_id ${:folder_id}} if {![info exists parent_id]} {set parent_id $folder_id} if {$base_table eq "cr_revisions"} { set attributes [list ci.item_id ci.name ci.publish_status acs_objects.object_type acs_objects.package_id] } else { set attributes [list bt.item_id ci.name ci.publish_status bt.object_type "bt.object_package_id as package_id"] } foreach a $select_attributes { if {$a eq "title"} {set a bt.title} lappend attributes $a } set type_selection_clause [:type_selection_clause -base_table $base_table -with_subtypes $with_subtypes] # :log "type_selection_clause -with_subtypes $with_subtypes returns $type_selection_clause" if {$count} { set attribute_selection "count(*)" set orderby "" ;# no need to order when we count set page_number "" ;# no pagination when count is used } else { set attribute_selection [join $attributes ,] } set cond [list] if {$type_selection_clause ne ""} {lappend cond $type_selection_clause} if {$where_clause ne ""} {lappend cond $where_clause} if {[info exists publish_status]} {lappend cond "ci.publish_status = :publish_status"} if {$base_table eq "cr_revisions"} { lappend cond "acs_objects.object_id = bt.revision_id" set acs_objects_table "acs_objects, " } else { lappend cond "ci.item_id = bt.item_id" set acs_objects_table "" } lappend cond "coalesce(ci.live_revision,ci.latest_revision) = bt.revision_id" if {$parent_id ne ""} { if {$with_children} { append from_clause ", (select $parent_id as item_id from dual union select item_id from cr_items where parent_id = $parent_id) children" lappend cond "ci.parent_id = children.item_id" } else { lappend cond "ci.parent_id = $parent_id" } } if {$page_number ne ""} { set limit $page_size set offset [expr {$page_size*($page_number-1)}] } else { set limit "" set offset "" } if {!$count} { # # In case the query is not explicitly referring to a context_id, # return the context_id of the item. The problem are queries # using "*" in the attribute list, which should be deprecated. # Before that we should walk through the common call patterns of # this function to check, if this is feasible. # # This local hack was necessary to deal with a recent fix that # honors now correctly changes in the context_id. Before this # change, e.g. "get_all_children" was returning due to the # nature of the call the context_id of the revision (not of the # item), although it was returning items. A following bug-fix # actually triggered this change. # https://cvs.openacs.org/changelog/OpenACS?cs=oacs-5-10%3Agustafn%3A20210308161117 # # TODO: remove me, when not necessary anymore. # if {[lsearch -glob $attributes *context_id*] == -1} { append attribute_selection {,(select context_id from acs_objects where object_id = ci.item_id)} } } set sql [::xo::dc select -vars $attribute_selection -from "$acs_objects_table cr_items ci, $base_table bt $from_clause" -where [join $cond " and "] -orderby $orderby -limit $limit -offset $offset] #:log "--sql=$sql" return $sqllock (scripted)
;mime_type (setter)
mk_insert_method (scripted)
;mk_save_method (scripted)
;new_persistent_object (scripted, public)
<instance of xo::db::CrClass> new_persistent_object \ [ -package_id package_id ] [ -creation_user creation_user ] \ [ -creation_ip creation_ip ] args [ args... ]Create a new content item of the actual class, configure it with the given arguments and insert it into the database. The XOTcl object is destroyed automatically on cleanup (end of a connection request).
- Switches:
- -package_id (optional)
- -creation_user (optional)
- -creation_ip (optional)
- Parameters:
- args (required)
- Returns:
- fully qualified object
- Testcases:
- xotcl_core_tutorial_4
:get_context package_id creation_user creation_ip # :log "ID [self] create $args" ad_try { :create ::0 {*}$args } on error {errorMsg} { ad_log error "CrClass create raises: $errorMsg" } # :log "ID [::0 serialize]" set item_id [::0 save_new -package_id $package_id -creation_user $creation_user -creation_ip $creation_ip] ::0 move ::$item_id ::$item_id destroy_on_cleanup return ::$item_idnon_cached_instance_var_patterns (setter)
remember_long_text_slots (scripted)
# # Keep "long_text_slots" in a separate array (for Oracle) # unset -nocomplain :long_text_slots foreach {slot_name slot} [array get :db_slot] { if {[$slot sqltype] eq "long_text"} { set :long_text_slots($slot_name) $slot } } # :log "--long_text_slots = [array names :long_text_slots]"storage_type (setter)
supertype (setter)
type_selection_clause (scripted)
if {$with_subtypes} { if {$base_table eq "cr_revisions"} { # do type selection manually return "acs_objects.object_type in ([:object_types_query])" } # the base-table defines contains the subtypes return "" } else { if {$base_table eq "cr_revisions"} { return "acs_objects.object_type = '${:object_type}'" } else { return "bt.object_type = '${:object_type}'" } }unknown (scripted)
# When this happens, this is most likely an error. Ease debugging # by writing the call stack to the error log. ::xo::show_stack :log "::xo::db::CrClass: unknown called with $obj $args"
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables