[Zope-CMF] Note on unique searchable ids
Raphael Ritz
r.ritz@biologie.hu-berlin.de
Fri, 13 Sep 2002 10:51:54 +0200
Hi,
the issue of adding unique ids to CMF content object instances
came up again so I thought I just post 'our' solution. I decided to
extend
the 'DefaultDublinCoreImpl' since my primary motivation was to replace
the URL currently given as identifier with something that is (hopefully)
more persistent (the URL breaks as soon as an object gets moved
or something along the path gets renamed).
Raphael
(Sorry for posting the whole stuff this way and not providing a
howto on cmf.zope.org but the site seems to be down again;
the mapping is obviously site specific to us but you get the idea ;-)
-----------------------------------------------------------------------------------------
Providing portal content with a unique searchable Id
Extended the 'DefaultDublinCoreImpl' class from the 'DublinCore.py'
modul
in 'zopehome/Products/' to provide methods for setting, getting, and
resetting an attribute called 'searchid' that is now available to all
content types that inherit from 'DefaultDublinCoreImpl'. For
sourcecode see
below.
Wrote a Python script called 'show' (located in 'portal_skins/custom')
to lookup individual searchids by searching the 'portal_catalog' and
to
display the result (if nothing is found, redirects to
'context.absolute_url()'
if exactly one is found, gets the objects view and if several are
found,
lists them by redirecting to 'search' appropriately).
Wrote another Python script called 'getURI' (located in
'portal_skins/custom')
to generate a URL based on the searchid of the form
'portalhome/show/searchid'
Added 'sid' as 'FieldIndex' to the 'portal_catalog'. If needed,
'SearchId'
could be added as 'TextIndex' -> on 'sid' you can sort, whereas on
'SearchId' you can use globbing.
Where ever this id of an object should be shown, add a line like
<p> The search Id of this document is <dtml-var SearchId missing="not
yet
defined>.</p>
to the corresponding 'view' or 'edit_form' methods.
Similar for a URI
<p> To reliably bookmark this page use <dtml-var getURI>.</p>
Source code
the additional class methods for the 'DefaultDublinCoreImpl'
-----------------------------------------------------------------------------
#
# additional methods for the NI portal
# Raphael Ritz, September 2002
#
# Class variable default for an upgrade
searchid = None
security.declarePublic( 'SearchId' )
def SearchId( self ):
"""
used for Dublin Core element Identifier as URI
"""
return self.sid()
security.declarePublic( 'sid' )
def sid( self ):
"""
searchable id; generated if first needed
used for the Dublin Core element identifier
as URI.
"""
searchid = self.searchid
if searchid is None:
# Upgrade.
searchid = self._setSid()
self.searchid = searchid
try:
self.reindexObject(idxs=['sid'])
except: # for backwards
compatibility
self.reindexObject()
return searchid
security.declareProtected( CMFCorePermissions.ManagePortal
, 'resetSid' )
def resetSid( self ):
"""
reset searchid to None (utility function for testing and
debugging)
"""
self.searchid = None
security.declarePrivate( '_setSid' )
def _setSid( self ):
metaTypeMapping = {'Database': 'DB',
'Portal External File': 'EF',
'Discussion Item': 'DI',
'Document': 'DO',
'ExternalFile': 'EF',
'Favorite': 'FA',
'UL File': 'UF',
'Portal Folder': 'PF',
'Portal Image': 'IM',
'Institute': 'IN',
'Journal': 'JO',
'Link': 'LI',
'CMF MailMessage': 'MM',
'NeuroEvent': 'NE',
'News Item': 'NI',
'Person': 'PE',
'Preprint': 'PR',
'Research Group': 'RG',
'Software': 'SW',
'Threaded Discussion': 'TD',
'Portal Topic': 'PT',
'WebResource': 'WR'
}
searchid = ''
if self.meta_type in metaTypeMapping.keys():
searchid = metaTypeMapping[self.meta_type]
else:
searchid = 'NS'
searchid = searchid + self.CreationDate()
# clean the string
allowedChar = string.letters + string.digits
tmp = ''
for c in searchid:
if c in allowedChar: tmp += c
searchid = tmp
# check whether this is unique using the portal_catalog
counter = 0
while self.portal_catalog.searchResults(sid = searchid) :
counter += 1
searchid = tmp + str(counter)
return searchid
-------------------------------------------------------------------------------
The Python script 'show' in 'portal_skins/custom'
-------------------------------------------------------------------------------
## Script (Python) "show"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=lookup the trailing sid
##
# queries the portal_catalog for sids given as subpath if present
# redirects to homepage/the items view/search if 0/1/more items
# were found (maybe home should be replaced by something else?)
request = container.REQUEST
RESPONSE = request.RESPONSE
target = traverse_subpath
if target:
results = context.portal_catalog.searchResults(sid=target)
else:
results = []
hits = len(results)
if not hits:
context.REQUEST.RESPONSE.redirect('%s' % ( context.absolute_url() ))
elif hits == 1:
context.REQUEST.RESPONSE.redirect('%s' % ( results[0].getURL() ))
else:
searchpar = ''
for item in target:
searchpar = searchpar + '&sid=' + item
searchstring = 'search?' + searchpar[1:]
context.REQUEST.RESPONSE.redirect('%s/%s' % ( context.absolute_url()
, searchstring ))
------------------------------------------------------------------------------
The Python script 'getURI' in 'portal_skins/custom'
------------------------------------------------------------------------------
## Script (Python) "getURI"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=based on SearchId
##
# generates an object URL based on the persistent
# searchable identifier SearchId
target = "%s/show/%s" % (container.absolute_url(), context.SearchId())
return target
--------------------------------------------------------------------------------