January 15 2008posted by Santi

Manage Relations within CPSSchemas

ent asked question is how to use CPSSchemas to manage relations between objects. We have not found another way that the use of “Internal Link Widget”, which has no guarantee about the deletion of linked object, or the one described here: http://www.cps-project.org/sections/documentation/users/creer_document_flexible , which is not a relation, but a containment of repetitive fields.


So, we have developed our own solution: a “KMKey Relation Field” and some “KMKey Relation Widgets” (at this moment, just one of them is developed, but will be someones more). They use is quite easy:

   1. Download KMKey using subversion: svn co https://svn.sourceforge.net/svnroot/kmkey/bundles/kmkey-3-head/
   2. Put or link all the products from your Zope Instance
   3. Compile the IncrementalSearch2 (sudo python2.4 setup.py install)
   4. Restart Zope and create a “CPSDefault Site”, selecting, at least, the "CPS Skins Themes", "CPS Subscriptions",  “KMKey Core” and “KMKey Widgets” profiles. If you have a created site, you can import these profiles using the portal_setup tool.
   5. Then you can create your own schema at portal_schemas, using KMKey Relation Field where you need
   6. Also you can create your own layout at portal_layouts, using KMKey Relation Widgets against the KMKey Relation Fields
   7. Then add your Type in portal_types, using your new schema and your new layout. Here is important to set “Product name” = “KMKeyCore” and “Product factory method” = “addKMRelationableDocument”
   8. Assign the proper workflow to your new type in .cps_workflow_configuration of your workspaces or your sections


That's all, you can use your new type and the relation will be effectively managed. If the related object is deleted, nothing happens, your relationship will be alive. If the related object is versioned, your relationship will be updated. You can also use some advanced options in the widget:

   1. Define the AdvancedQuery expression using TALES: python:Eq('portal_type', 'Document') & Eq('review_state', 'work')
   2. Define the sort_on criteria
   3.Define a TALES expression to compose the value to show from the related object (by default its Title)
   4. Define a TALES expression to filter the row: python:'mystring' in brain.Title

Internally, all this is implemented using the structure of portal_repository and portal_proxies of CPS. All objects are stored in the portal_repository, with an Id like this one: 9999999_0001, where 9999999 is an unique docid and the 0001 is the object revision. Then there are one or some proxies in the objects tree linking to this revisions. Our relations are implemented remembering the docid of the related object, and fetching the last revision of that object from the repository when needed. The last step was guarantee that the related object is not deleted from the repository, even if all its proxies are deleted. This is done inserting a false proxy in the proxies_tool after set a relation, an removing it when the relating object is deleted (this is not nice at all, but the only way found without patching CPS itself)