KM-Library


originally by Carsten Clasohm and Sarah Arnold
June 2000, revised November, 2000
ported to ACS4 mostly by Dirk Gomez

We've rebuilt the library on top of a lot of procs that deal with meta and object data. The procs are organized into Tcl collections that we'll go through in this doc. The data model is described in KM Data Model. Also see the flowchart which shows all possible paths within the library.

We have tried to write short, well-named and highly cohesive procs that never use upvar or uplevel. We have tried to keep site navigation and excursion handling on the pages. It is very difficult to figure out what is going on with navigation if it's buried in a proc somewhere. The idea is that when you look at a page, you see what variables are coming in, you see the procs that deal with the data machinery and display, you see how the page handles the navigation from the page. See below about paths to follow the navigation mechanism.

The procs are strictly sorted into their own libraries. A proc found in km-display will never retrieve data from oracle. A proc in km-object-data does not display HTML.
km-categories.tcl holds procs that have to do with categories and some of these do display something. (these procs are part of 's categorization system which is part of the ACS categorization.)

km-defs.tcl has library core-procs having to do with metadata, building form fields, object access control, checking user input and excursions (aka paths).

  1. Abstract Data Types

    1. text Text data stored together with a value of html_p in one row of sn_content.
    2. option Multiple choice data stored in sn_object_option_map, refers to sn_answer_options
    3. category Category data that maps the object to site-wide categories in site_wide_category_map
    4. composite A question composed of one or more children questions which are mapped in sn_question_object_type_map.
    5. date A date stored as text in sn_content but required to be a valid date.
    6. integer An integer stored as text in sn_content but required to be a valid integer.
    7. file An uploaded document that can be found in the document_uploads directory, the name of the file is stored in sn_content.
    8. object_link Maps objects to other objects in sn_links, refers to a comment in sn_link_comments.
    9. user_link Maps objects to users in sn_links, doesn't have a comment, but could.
    10. child_object The answer to this question is the completed content of another object type. The permissions and the public/private status of this child object are exactly the same as for the parent object. If the parent object is public and all mandatory questions of a child object get answered, it will automatically get the public status. If the parent object gets deleted, so are all its child objects.
    11. nephew_object The answer to this question is again the completed content of another object type. The permissions of uncle and nephew objects can be set seperately. To publish an uncle object, at least one nephew object must be published at the same time. After publishing of the uncle object, nephew objects can be published and unpublished seperately. If the last public nephew object of a public uncle object gets private, so does the uncle object. If an uncle object gets delete, so do all its nephew objects. This special abstract data type was needed for People 's Project and Demand descriptions.

  2. Metadata (km-00-defs.tcl)

    There is one main proc responsible for getting metadata- km_get_questions. km_get_questions returns all visible question_ids and various other metadata attributes for any given object type as a keyed list of lists. km_get_question returns one question and is usually used to return the next or previous question in the question list by calling it with the "-next_p" or "-previous_p" options.

    The other important metadata procs are km_get_all_object_types and km_object_type_attributes, which return useful stuff about the object types. The latter is used on almost every single page in the library, since it returns everything we need to know to display a page for any given object type.

    km_static caches information about objects whose value is more or less static throughout the system's life time. The first time a particular information is being looked for, this information is being loaded from the database into the cache. km_static does _not_ do any error checking at the moment. It is also not the smartest caching system under the sun (not yet at least):

    km_conn works very much like ad_conn: it caches information on a library object on a per-request basis. Put everything that could be a of interest for an object here and retrieve it from this function. Most of the km_conn cache is set in km_check_object_id.

  3. Building dynamic forms (km-display.tcl)

    km_get_form builds a form of questions for any object type. It takes the questions from km_get_questions and presents each according to its

    1. Abstract data type
    2. Presentation type

    There are various display procs that are named after the abstract data types that are used for them, i.e. km_user_link_field, km_option_field. Also important is km_get_form_field, a display proc that knows how to call procs that produce HTML tags from the metadata presentation types. EVERY form in the library that handles object data is produced by calling this proc. object-edit.tcl makes only one call to km_get_form to produce the entire form. one-question-edit.tcl also calls this proc with a question-id.

    Only small parts of the library have been templated yet, both because we were working under heavy timeload and because of km_get_form's complexity.

  4. User Input

    The center proc in the family of user-input procs is km_check_input. It takes a list of keys, a list of values and an object type and determines if there has been insufficent or invalid data entered as values. It does this by calling km_required_questions and then compares a list of required fields for this object type with the keys and values.

    Important here is the proc km_sort_form, which takes all the various key-value pairs coming in from a input form and assembles them into meaningful lists according to the abstract data type. So, for example, a question having abstract data type text will have a sibling variable "html_p" that is sorted by this procedure into a value tuple, where the first value is the text itself and the second is the boolean value. Mulitiple-select variables are also sorted into lists matched to one key. Also: km_assemble_dates. This proc takes n variables of the triple form var:year var:month var:day and assembles them to the variable var, whose value is "YY-MM-DD". (Similar to the date_widget but more flexible for the method of dynamic form generation required in this system.) var is run through the proc date_p to make sure that this assembled thing is really a date.

    If check_input finds any reason to complain, it returns a a tuple: the number of complaints and the message strings. These can then be easily formatted to ad_return_complaint on the page.

  5. Linking

  6. Creating an object (km-object-data.tcl)

    This is done by km_create_object.

  7. Saving object data (km-object-data.tcl)

    The central proc in the family of procs that save object data is called km_save_object_data. It takes a list of keys, a list of values, a user_id and an object_id as arguments. It saves all data of whatever abstract data type if possible.

    km_save_object_data actually doesn't save any data itself, it calls procs to deal with the data by abstract data type.

    This proc only saves object data of other abstract data types for an object_id that already exists. (it doesn't make sense to categorize or link an object that doesn't exist.)

  8. Retrieving object data

    In principle, data is retrieved in the same way it is saved: divided into abstract data types and then picked out accordingly. The proc that handles this is known as km_get_object_data. It only needs an object_id and it returns a key list of lists. Check out the form of the return lists in the proc itself. It returns everything you need to display this data (but this proc does NOT display data.) If you only want the data on a few questions or even just one question, then pass a list of just these questions as an optional argument. Otherwise it gets data for every single question that can be asked about this object.

    Each question supplied to km_get_object_data is looped through and answered according to abstract data type. The answer is retrieved by calling a proc that know how to get this particular type of data. Many of the other procs that km_get_object_data calls are also in km-object-data.tcl:
    km_get_answer_options, km_get_user_links.

    km_get_linked_objects gets all data about linked objects for a question of abstract data type "object_link". It is found in km_links.tcl. (km_get_child_objects is actually in km-links.tcl, too, since "child_object" a kind of link is.
    km_get_categories gets all category data for a particular question of abstract data type "categorization". It is found in km_categories.tcl.

  9. Buttons

    The km8_button_panel returns datasources for the 5 buttons that appear as a navigation panel at the bottom of one-question-edit.tcl. They allow the user to go to a lot of places that can only be determined by analysing the name of the submit button. Accordingly, we have procs that create submit buttons of the style "my_submit_button_name:some_important_number".

    Related to these procs is km-defs' km_button_list, which returns a list of all possible submit button names in .

  10. Dates (km-display.tcl, km-defs.tcl)

    There are also some special little procs that do date stuff. For example, km_break_date ....breaks a date into 3 parts. Or km_empty_date_p determines if a date has any empty fields at all. There are some default date procs in km-defs.tcl.: km_default_day, km_today, km_default_year, km_default_month. The special proc for is km_library_date, which calculates a default date for beginning and ending projects.

  11. Branches(km-branch.tcl)

    Branches are not abstract data types! Branches are how we call answer-dependent question sequences in the library. For instance, you have a question "Who did you vote for?". If the answer was "George W. Bush", then the following question might be "What reasons do you have to believe that the Republican party will help you personally?" If your answer was "Al Gore", then the following question might be "Did you vote Democratic because you were pleased with the present government?"

    Refer to the km-library document to grasp the finer points of the question hierarchies for branches. The most important procs are km_get_root_branch, which returns the highest node of the branch hierarchy for given question_id. Similarly, km_root_branch_p determines if this is a question is at all a branch node that has children. Important here is the concept of "active branches". An active branch is one where all the questions are descendents of an answer that has been chosen higher up in the branch tree. If later, one answer higher up is changed, then those questions and answers below it are no longer considered "active" and will not be displayed in the interface. This is why km_active_branch_p requires the root_question_id of a branch AND the object_id. Each object will have its own specific version of the active branch path. The most critical proc is km_next_branch. Alter with care!!!! It takes a question_id and an answer and, analysing them according to the abstract data type, determines which question should follow. It uses the default branch if it can't determine what it should return, or empty, if there are no children. This proc is used when navigating one-question-edit.tcl form "previous" question to "next". Make sure you look at the km8_button_panel in km-display.tcl that predetermines the previous and next questions when displaying one-question-edit.tcl. And also, km_get_question in km-defs.tcl, which does NO branch analysis but works together with km_next_branch in one-question-edit-2.tcl to determine what the next question will be.

  12. Access Control (km-access-procs.tcl)

    In contrast to 7, the Library now uses the system-wide permissioning system for controlling access to the Knowledge Objects. Only a small part of km-access-procs.tcl is concerned with the actual permission checks - the large rest of the code does some useful things like retrieving general object information in one query.

    1. km_check_object_id, km_check_object_type_id

      These versatile procs should be used on all pages to which an object or type ID may be passed. They check if the object or type exists, has been deleted, is readable or writeable by the given user, and also can print error messages. Note that km_check_object_id also checks permissions for the object type.

    2. Other Access Control Procs

      Apart from that, there are also procs for checking if a given user is a library administrator, may change the owner of an object and may read or modify an object or object type.

  13. Browsing (km-browse.tcl)

    A couple of display procs used by browse-one-type, browse-one-category and the object-view family of pages can be found here.

    The only interesting proc is km_output_object_list, which is used at a couple of places to output lists of objects (name, overview, author), possibly with Link buttons when the user is on an excursion. It checks the access permissions in its own way, since for speed reasons we have to use SQL joins and cannot use the Tcl procs defined in km-access.

  14. Category Hierarchy (km-categories.tcl) XXX Tomislav

    All the stuff related to categories resides here. We use the standard categories from the ACS, but need some helper procs to deal with them.

    1. km_category_table

      When the user browses objects of one type, he can navigate through the associated category tree. This proc builds a subtree starting at a given question or category, and displays it as a HTML table. The count of objects below each category is passed in as a parameter.

    2. km_get_child_categories

      Returns all the categories associated with the given question as a list of tuples holding the category_id and the indented category name. This is used for data entry, where we want to display an indented list in a selection box.

    3. km_get_category_counts

      Counts how many objects there are for a category and its subcategories. The result can then be used for km_category_table.

    4. Misc.

      Mapping between objects and categories and between questions and category trees; procs for handling category trees (determing the root category, e.g.); small display procs.

  15. Reuse Feedback (km-feedback.tcl)

    Editing and display of general comments and reuse feedback for knowledge objects. Uses the site-wide service general-feedback.

  16. User Customisation (km-users.tcl)

    Procs used to display the users Workspace (saved items), and his own objects (with some information about their current state). This is also the place for hooking into ACS' system of listing user contributions and new stuff (km_contributions).


sarnold@arsdigita.com