|
Dieter Maurer wrote: As soon as you index the content, you will be interested to distinguish between a modification in the primary content and some meta data (as it has big repercussions on the speed of the reindexing). I agree, but perhaps we can find a compromise that fits all needs. I propose to use pluggable modification utilities. The container related events are already fired by only two functions (setitem and uncontained). If we introduce a third one for object modification (e.g. update or modify and an additional annotate if needed), we can replace these functions with callable utilities, which are responsible for performing the changes and firing the events. It's then up these components which events are actually used. Direct calls of ObjectModifiedEvents can then be marked as deprecated to ensure that all applications will use these pluggable modifiers. Regards, Uwe The following code should make clear what I mean: #! python import doctest, unittest, zope from zope.app import zapi from zope.interface import Interface, implements from zope.app.event.objectevent import ObjectModifiedEvent from zope.app.event.interfaces import IObjectModifiedEvent class IPluggableModifier(Interface) : """ A pluggable modifier can be used to replace the existing modification mechanism in Zope. It should be used in all places where other systems are notified about changes. The implementation must ensure that at least one IObjectModifiedEvent is fired if an object's state has been changed. """ def __call__(self, obj, interface, **kw) : """ Performs the update and fires an IObjectModifiedEvent. It's up to the plugin which specialization of IObjectModifiedEvent is actually used. Returns the modified object or None if the object could not be modified. """ class DefaultModifier(object) : """ Implements a default behavior that mimics Zope3's current modification event handling. Setup : >>> from zope.component import provideUtility >>> provideUtility(DefaultModifier(), IPluggableModifier) >>> events = [] >>> zope.event.subscribers.append(events.append) >>> class Sample(object) : pass Usage : >>> modify = zapi.getUtility(IPluggableModifier) >>> sample = Sample() >>> result = modify(sample, None, title='Test', description='Example') >>> result == sample True >>> IObjectModifiedEvent.providedBy(events[0]) True >>> sample.title 'Test' >>> sample.description 'Example' """ implements(IPluggableModifier) def __call__(self, obj, interface, **kw) : """ Modifies an object and fires an IObjectModifiedEvent. """ if interface is not None : obj = interface(obj) for key, value in kw.items() : setattr(obj, key, value) zope.event.notify(ObjectModifiedEvent(obj)) return obj class ValueChangedEvent(object) : """ A modification event that keeps additional information about the used interface, the old and new values. """ def __init__(self, object, interface, key, old_value, new_value) : self.object = object self.interface = interface self.key = key self.old_value = old_value self.new_value = new_value class BetterModifier(object) : """ Implements a modification behavior that fires more informative events for more efficient versioning and reindexing. Setup : >>> from zope.component import provideUtility >>> provideUtility(BetterModifier(), IPluggableModifier) >>> events = [] >>> zope.event.subscribers.append(events.append) >>> class Sample(object) : pass Usage : >>> modify = zapi.getUtility(IPluggableModifier) >>> sample = Sample() >>> result = modify(sample, None, title='Test', description='Example') >>> result == sample True >>> sample.title 'Test' >>> sample.description 'Example' >>> for x in events : print x.__class__.__name__ ValueChangedEvent ValueChangedEvent ObjectModifiedEvent """ implements(IPluggableModifier) undefined = object() def __call__(self, obj, interface, **kw) : """ Modifies an object and fires an IObjectModifiedEvent. """ if interface is not None : obj = interface(obj) for key, value in kw.items() : old = getattr(obj, key, self.undefined) if old != value : setattr(obj, key, value) event = ValueChangedEvent(obj, interface, key, old, value) zope.event.notify(event) zope.event.notify(ObjectModifiedEvent(obj)) return obj from doctest import DocTestSuite def test_suite(): return unittest.TestSuite(( DocTestSuite(), )) if __name__ == '__main__': unittest.main(defaultTest='test_suite') |
_______________________________________________ Zope3-dev mailing list [email protected] Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
