Index: openacs-4/packages/acs-content-repository/www/doc/tutorial.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/www/doc/tutorial.adp,v diff -u -r1.2.2.3 -r1.2.2.4 --- openacs-4/packages/acs-content-repository/www/doc/tutorial.adp 9 Jun 2016 13:03:11 -0000 1.2.2.3 +++ openacs-4/packages/acs-content-repository/www/doc/tutorial.adp 1 Jul 2016 09:17:32 -0000 1.2.2.4 @@ -6,12 +6,13 @@ by Jade Rubick
Let's say you're a developer making a package for OpenACS. -You've heard statements like, "every package should use the content -repository", or maybe a developer has suggested that you use it. Or -maybe you just stumbled across it. Why would you want to spend your -time reading this document and wasting a good afternoon when you -could get started coding right away?
+Let's say you're a developer making a package for +OpenACS. You've heard statements like, "every package +should use the content repository", or maybe a developer has +suggested that you use it. Or maybe you just stumbled across it. +Why would you want to spend your time reading this document and +wasting a good afternoon when you could get started coding right +away?
The simple answer is that the content repository (CR) gives you many different things for free:
First of all, let's get some terminology out of the way. Columns -of a table are referred to as attributes in content -repository-speak.
+First of all, let's get some terminology out of the way. +Columns of a table are referred to as attributes in +content repository-speak.
The steps to set up your data model are as follows:The first step is to decide on what part of a Task you'd you'd -like to have under revision control, and what portion you'd like to -have just one version of. In our case, the only thing we wouldn't -want under version control is the Task Number. This will be a -unique identifier for the task, and we don't want that changing -every time someone edits it.
+The first step is to decide on what part of a Task you'd +you'd like to have under revision control, and what portion +you'd like to have just one version of. In our case, the only +thing we wouldn't want under version control is the Task +Number. This will be a unique identifier for the task, and we +don't want that changing every time someone edits it.
For our simple example:
Title - want versions @@ -77,9 +78,10 @@ without versioned attributes.Convention: often, developers will name the first table -by what it is (in my case pm_tasks), and the second, -versioned table by the same name, but with _revisions at the end. -Thus, I'll name my second table pm_tasks_revisions.
+by what it is (in my case pm_tasks), and the +second, versioned table by the same name, but with _revisions at +the end. Thus, I'll name my second table +pm_tasks_revisions. This is actually very easy:Versioned portion:
@@ -117,12 +119,12 @@One thing you have to be careful of when creating these tables is that there are no columns that have the same names as any of the columns in the
+tables for you, but they won't be created if the names +conflict. I'll describe what these views are later, but they +are useful. You were warned.cr_items
andcr_revisions
-tables. For example, you can't call you key on the +tables. For example, you can't call you key on the pm_tasks_revisions tablerevision_id
. Why? There are some views that are automatically generated that combine these -tables for you, but they won't be created if the names conflict. -I'll describe what these views are later, but they are useful. You -were warned.Notice that each table uses as its primary key a reference to either the
cr_revisions
table or thecr_items
table. A content item is basically @@ -134,11 +136,11 @@sql/postgresql/project-manager-create.sql
file. Your name will be different of course.Describe attributes
-After we've created the two tables, we need to let the content -repository know that we have a new type of structured data that we -are storing in the content repository. Tasks are a "content type", -because they have data associated with them, such as when they are -due, and what needs to be done.
+After we've created the two tables, we need to let the +content repository know that we have a new type of structured data +that we are storing in the content repository. Tasks are a +"content type", because they have data associated with +them, such as when they are due, and what needs to be done.
I thus need to to
--create the content type @@ -155,8 +157,9 @@You then need to add in all the attributes, so that the content repository can do some magic things behind the scenes. The content -repository doesn't know about what's inside of the pm_tasks -and pm_tasks_revisions tables, so we teach it:
+repository doesn't know about what's inside of the +pm_tasks and pm_tasks_revisions tables, so we +teach it:-- add in attributes @@ -195,10 +198,10 @@-Side effect: once you've created the content type, the -content repository creates a view for you called +Side effect: once you've created the +content type, the content repository creates a view for you called
pm_tasks_revisionsx
. Note the x at the end of the -name. If you're using Postgres, I believe it will also create a +name. If you're using Postgres, I believe it will also create a view for you calledpm_tasks_revisionsi
Why are these two views created? the x view is created for @@ -212,38 +215,40 @@ table or
+repository API. The advantage is that someday you'll be able to +do really cool stuff with it, like automatically generate +interfaces that take advantage of the new columns and tables +you've added. Another nice thing is that all that messy +business of defining your attributes through the API is taken care +of.alter table add column
statements in SQL, but this also adds in some meta-data that will be useful to you. The disadvantage is that you have to call the content -repository API. The advantage is that someday you'll be able to do -really cool stuff with it, like automatically generate interfaces -that take advantage of the new columns and tables you've added. -Another nice thing is that all that messy business of defining your -attributes through the API is taken care of.Types is the content repository are another term for -tables, although that doesn't explain it completely. Types are also -kept track of within OpenACS, in the
+tables, although that doesn't explain it completely. Types are +also kept track of within OpenACS, in the +acs_object_types
-table, so the system knows about the tables you create, and can do -some intelligent things with them.acs_object_types
table, so the system knows about the +tables you create, and can do some intelligent things with +them.A lot of the intelligent things you can do with this information is still being built. But imagine for example that you -are using the project manager package I've written. You work at an -ice cream company, and every task that is done also has an -associated ice cream flavor with it (yeah, this isn't a good +are using the project manager package I've written. You work at +an ice cream company, and every task that is done also has an +associated ice cream flavor with it (yeah, this isn't a good example, but pay attention anyway). If I've written the project manager to take advantage of it, when you add in this extra attribute to the pm_tasks_revisions table, the UI aspects will be -automatically taken care of. You'll be able to select a flavor when -you edit a task, and it will be shown on the task view page. This -is the direction OpenACS development is going, and it will be +automatically taken care of. You'll be able to select a flavor +when you edit a task, and it will be shown on the task view page. +This is the direction OpenACS development is going, and it will be really really cool!
First, I'm going to describe how to extend other content -repository tables using the CR API. Then, I'll describe how to set -up your own tables as well:
+repository tables using the CR API. Then, I'll describe how to +set up your own tables as well:As you recall from earlier in this page, attributes are just another term for columns in a table. The Content Repository has a mechanism for adding and removing columns via the pl/sql API. If you check your /api-doc:
/api-doc/plsql-subprogram-one?type=FUNCTION&name=content%5ftype%5f%5fcreate%5fattribute
-, you'll see that there is a way to extend the columns +, you'll see that there is a way to extend the columns programmatically.Why would you want to do this? For project manager, I decided to do this because I wanted to customize my local version of the @@ -300,43 +305,44 @@ You then need to define a couple of functions, that do all the nasty work of putting everything in the right tables. The general idea behind it is that the revisioned information is never changed, -but added to. Here's how it works. When you create a new task, you -call the
pm_task__new_task_item
- function (which we'll -write in a little bit). This function creates both a new content -item, and a new content revision. Information is actually stored in -four tables, believe it or not:cr_revisions
+but added to. Here's how it works. When you create a new task, +you call thepm_task__new_task_item
+ function (which +we'll write in a little bit). This function creates both a new +content item, and a new content revision. Information is actually +stored in four tables, believe it or not: +cr_revisions
+,cr_items
, -cr_items
-,pm_tasks
-, and -pm_tasks_revisions
-. The task number is stored in -pm_tasks, the title and description are stored in -pm_tasks_revisions, and some additional information like who -entered the information is stored in cr_revisions and cr_items. -Whenever you make a change to this item, you don't change the table -yourself, but add +pm_tasks
+, andpm_tasks_revisions
+. The +task number is stored in pm_tasks, the title and description are +stored in pm_tasks_revisions, and some additional information like +who entered the information is stored in cr_revisions and cr_items. +Whenever you make a change to this item, you don't change the +table yourself, but add a revision, using yourpm_task__new_task_revision
- function (which we'll write -in a little bit). This function adds another revision, but + function (which we'll +write in a little bit). This function adds another revision, but not - another item or cr_item. After you've added another -revision, you'll have two revisions and one item. Two entries in -cr_revisions (and pm_tasks_revisions), and one item in cr_items and -pm_tasks. The cr_revisions table keeps track of which item is the -most recent, and which item is "live". For the edit-this-page -application, for example, this is used to keep track of which -revision to a page is actually being served to users. In your code, -you'll use your pm_tasks_revisionsx view, which joins the -pm_tasks_revisions table with the cr_revisions table (and it might -even join in cr_items -- I forget at the moment). + another item or cr_item. After you've added +another revision, you'll have two revisions and one item. Two +entries in cr_revisions (and pm_tasks_revisions), and one item in +cr_items and pm_tasks. The cr_revisions table keeps track of which +item is the most recent, and which item is "live". For +the edit-this-page application, for example, this is used to keep +track of which revision to a page is actually being served to +users. In your code, you'll use your pm_tasks_revisionsx view, +which joins the pm_tasks_revisions table with the cr_revisions +table (and it might even join in cr_items -- I forget at the +moment).Defining your pl/sql functions
You can see the actual functions used in project manager via the -CVS browser's entry for project-manager +CVS browser's entry for project-manager . Note these are a little more expanded than what I've used in the examples above.@@ -509,24 +515,27 @@ cr_items:-item_id - unique id for this item, will be -different than the revision_idcr_revisions:
parent_id - used to group items into a hierarchy (see -below)
name - this is used to make a URL by the content repository. -It must be unique per content folder. You can use a number, or -something like project_231. One way to do this is to set it equal -to a title plus the item_id.
locale - not sure, probably for internationalization -support
live_revision - this is equal to the cr_revision table's -revision_id that is the live version
latest_revision - this is equal to the cr_revision table's -revision_id that is the latest version
publish_status - not sure
content_type - not sure
storage_type - not sure, probably text or binary?
storage_area_key - not sure
tree_sortkey - a utility column used in hierarchical -queries.
+item_id - unique id for this item, +will be different than the revision_id
parent_id - used to group items into a hierarchy +(see below)
name - this is used to make a URL by the content +repository. It must be unique per content folder. You can use a +number, or something like project_231. One way to do this is to set +it equal to a title plus the item_id.
locale - not sure, probably for +internationalization support
live_revision - this is equal to the cr_revision +table's revision_id that is the live version
latest_revision - this is equal to the cr_revision +table's revision_id that is the latest version
publish_status - not sure
content_type - not sure
storage_type - not sure, probably text or +binary?
storage_area_key - not sure
tree_sortkey - a utility column used in +hierarchical queries.
-revision_id - a unique id for this revision.@@ -544,8 +553,8 @@
item_id - a reference to the item_id for this revision
title - you can use this for your application. For example, -My Big Project
description - you can use this for your application, as a -longer description.
publish_date - the date this was published. Not sure if this -is for your use, or internal
mime_type - the mime type.
nls_language - I believe this is for +revision_id - a unique id for this +revision.
item_id - a reference to the item_id for this +revision
title - you can use this for your application. For +example, My Big Project
description - you can use this for your +application, as a longer description.
publish_date - the date this was published. Not +sure if this is for your use, or internal
mime_type - the mime type.
nls_language - I believe this is for internationalization
lob - the binary content.
content - the text content.
content_length - the length of the text or binary content?
Using this structure is optional, but useful in many circumstances.
The facility for this is built into the
cr_items
-data model. This makes sense, because you wouldn't want your -hierarchy associated with each revision. Here's how Postgres +data model. This makes sense, because you wouldn't want your +hierarchy associated with each revision. Here's how Postgres describes thecr_items
table:Table "public.cr_items" @@ -576,16 +585,16 @@ give the application its own root directory. Because the content repository is shared among applications, this separates it off from other applications. They can still use the items in your -application, but it must be a more deliberate process. If you don't -create your own root directory, you may see strange-looking data -from other applications in your application, or see your -application's data in other applications. There are times when -you'll want to do this, but probably not until you're much more -familiar with the content repository. Another reason for creating -your own root repository is that you application may be mounted -several times. If you want to separate the directory structure -between instances of your application, you need to create your own -root directory: +application, but it must be a more deliberate process. If you +don't create your own root directory, you may see +strange-looking data from other applications in your application, +or see your application's data in other applications. There are +times when you'll want to do this, but probably not until +you're much more familiar with the content repository. Another +reason for creating your own root repository is that you +application may be mounted several times. If you want to separate +the directory structure between instances of your application, you +need to create your own root directory:Note that this example is for projects rather than tasks. This is -because for the application I'm writing, projects are what tasks -are stored inside of. A project has many component tasks. If you -were writing another application, or if I wasn't doing anythign -with projects, then this would be creating a folder for just tasks. +because for the application I'm writing, projects are what +tasks are stored inside of. A project has many component tasks. If +you were writing another application, or if I wasn't doing +anythign with projects, then this would be creating a folder for +just tasks.-- Creates and returns a unique name for new project folders @@ -646,34 +655,35 @@Typically, this definition would go in your
-sql/postgresql/project-manager-create.sql
file. If this file is broken in several parts, this would go in the project-manager-create-functions.sql portion.Once you've created your root directory, you will set the +
Once you've created your root directory, you will set the
-parent_id
of your items to the id for the new root -repository (in our case, it's returned from the +repository (in our case, it's returned from thepm_project__new_root_folder function
)In the project-manager application, we'll create a root +
In the project-manager application, we'll create a root repository, and make all projects under that root repository. That -means they'll all have a
parent_id
set to the root +means they'll all have aparent_id
set to the root repository. However, we also want to make projects that are sub-projects of other projects. In that case, we will set theparent_id
of the sub-project to theitem_id
of the parent.Understanding folders
For a little while now, we have been talking about folders, but we -haven't delved into what CR folders are. Folders are sub-classes of -cr_items
-, and the only real difference is that they -contain no data, except for a label and description. -If you create folders for your application, then you'll need to -make sure you manage them along with your other objects. For +haven't delved into what CR folders are. Folders are +sub-classes of
cr_items
+, and the only real difference +is that they contain no data, except for a label and description. +If you create folders for your application, then you'll need +to make sure you manage them along with your other objects. For example, if you were to add a folder for each of your objects, then you would probably want to make sure you delete the folder when you delete the object.
@@ -683,7 +693,7 @@ install the project-manager in two parts of your web server, for example, it should have two different root folders). When your application is running, it can determine the root folder by -searching the cr_folders table. Here's the definition of that +searching the cr_folders table. Here's the definition of that table:Table "public.cr_folders" @@ -715,14 +725,14 @@Drop scripts
If you have problems with your drop script in OpenACS 4.6.2, then -Tammy's +Tammy's drop scripts might be of interest to you.Using your data model
You now have a shiny new data model that handles revisions and all -sorts of other things we haven't gotten to yet. Now, in your Tcl -pages and your ps/sql code, you can... +sorts of other things we haven't gotten to yet. Now, in your +Tcl pages and your ps/sql code, you can...
Get latest revision (Tcl) set live_revision_id [db_exec_plsql get_live_revision {select @@ -740,7 +750,7 @@
- OpenACS Content Repository docs
- -Dave's page on Using the Content Repository
+Dave's page on Using the Content RepositoryReference: Definitions
@@ -790,7 +800,7 @@
Troubleshooting
One problem I ran into while trying to get my SQL create and drop -scripts working was that sometimes I wasn't able to delete a +scripts working was that sometimes I wasn't able to delete a content type because I would get errors like these:Referential Integrity: attempting to delete live_revision: 658 @@ -808,8 +818,8 @@ Really, however, what you need to do is make sure your __delete and drop scripts first go through and delete all children of those -items. I'm not sure if you need to delete the items themselves -- I -believe they may be dropped by themselves when the tables are +items. I'm not sure if you need to delete the items themselves +-- I believe they may be dropped by themselves when the tables are dropped, because of thecascade
portion of the SQL data model.