cybertools/relation/registry.py
helmutm cb9dc6219f more clean-up of code; invalidating of relations as a consequence of object removal is now fully event-based
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@660 fd906abe-77d9-0310-91a1-e0d9ade77398
2005-11-06 11:11:05 +00:00

179 lines
5.3 KiB
Python

#
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Implementation of the utilities needed for the relations package.
$Id$
"""
from persistent import Persistent
from zope.interface import Interface, Attribute, implements
from zope.app import zapi
from zope.app.catalog.catalog import Catalog
from zope.app.catalog.field import FieldIndex
from zope.app.intid.interfaces import IIntIds
from zope.app.location.interfaces import ILocation
from zope.event import notify
from zope.app.event.objectevent import ObjectEvent
from zope.security.proxy import removeSecurityProxy
from interfaces import IRelationsRegistry, IRelationInvalidatedEvent
class DummyRelationsRegistry(object):
""" Dummy implementation for demonstration and test purposes.
"""
implements(IRelationsRegistry)
def __init__(self):
self.relations = []
def register(self, relation):
if relation not in self.relations:
self.relations.append(relation)
def unregister(self, relation):
if relation in self.relations:
self.relations.remove(relation)
def query(self, **kw):
result = []
for r in self.relations:
hit = True
for k in kw:
if ((k == 'relationship' and r.__class__ != kw[k])
or (k != 'relationship'
and (not hasattr(r, k) or getattr(r, k) != kw[k]))):
hit = False
break
if hit:
result.append(r)
return result
class RelationsRegistry(Catalog):
""" Local utility for registering (cataloguing) and searching relations.
"""
implements(IRelationsRegistry)
def setupIndexes(self):
for idx in ('relationship', 'first', 'second', 'third'):
if idx not in self:
self[idx] = FieldIndex(idx, IIndexableRelation)
def register(self, relation):
#self.setupIndexes()
self.index_doc(_getUid(relation), relation)
def unregister(self, relation):
self.unindex_doc(_getUid(relation))
def query(self, **kw):
for k in kw:
if k == 'relationship':
quString = _getClassString(kw[k])
else:
quString = _getUid(kw[k])
# set min, max
kw[k] = (quString, quString)
return self.searchResults(**kw)
class IIndexableRelation(Interface):
""" Provides the attributes needed for indexing relation objects in
a catalog-based registry.
"""
class IndexableRelationAdapter(object):
""" Adapter for providing the attributes needed for indexing
relation objects.
"""
implements(IIndexableRelation)
def __init__(self, context):
self.context = context
def getRelationship(self):
return _getRelationship(self.context)
relationship = property(getRelationship)
def __getattr__(self, attr):
value = getattr(self.context, attr)
if isinstance(value, Persistent):
return _getUid(value)
else:
return value
# helper functions
def _getUid(ob):
return zapi.getUtility(IIntIds).getId(ob)
def _getRelationship(relation):
return _getClassString(removeSecurityProxy(relation).__class__)
def _getClassString(cls):
return '%s.%s' % (cls.__module__, cls.__name__)
# events and handlers
class RelationInvalidatedEvent(ObjectEvent):
implements(IRelationInvalidatedEvent)
def invalidateRelations(context, event):
""" Handles IObjectRemoved event: sends out an IRelationInvalidatedEvent
for all relations the object to be removed is involved in.
"""
relations = []
registry = zapi.getUtility(IRelationsRegistry)
for attr in ('first', 'second', 'third'):
relations = registry.query(**{attr: context})
for relation in relations:
notify(RelationInvalidatedEvent(relation))
def removeRelation(context, event):
""" Handles IRelationInvalidatedEvent by unregistering the relation
and removing it from its container (if appropriate) and the IntIds
utility.
"""
registry = zapi.getUtility(IRelationsRegistry)
registry.unregister(context)
if ILocation.providedBy(context):
parent = zapi.getParent(context)
if parent is not None:
del parent[context]
intids = zapi.getUtility(IIntIds)
intids.unregister(context)
def setupIndexes(context, event):
""" Handles IObjectCreated event for the RelationsRegistry utility
and creates the indexes needed.
"""
if isinstance(context, RelationsRegistry):
context.setupIndexes()