Plone的事件体系
Plone的事件体系
http://www.315ok.org/blogfolder/96
http://www.315ok.org/logo.png
Plone的事件体系
Plone的事件体系
Zope3带给Zope2最好的东西是Event 系统。 这使得可以容易地从任何地方发出事件或者注册事件的预定者。Event是同步的——触发代码将被锁定直到所有event handlers完成;并且event handlers不可排序,不能保证event handlers 被调用的顺序。
定义event的新类型非常简单,只需要一个标示event的接口和一个实际的类实现。
Event预定者被用ZCML注册:
对象事件
Zope 和 Plone 触发一些通常的事件,我们称之为对象事件,如当一个内容对象在容器中被添加、删除或者移动,或者当被首次创建、修改、拷贝时,就触发对象事件。这些事件都生成于zope.component.interfaces.IObjectEvent.
我们为对象事件注册预定者时,和其他类型的事件一样,但通常对于对象事件,我们在触发它时,往往针对特定类型的对象。也就是说我们在注册对象事件预定者时,往往针对对象类型和事件类型两个接口:
然而,容器对象的事件会被重新分发到该容器里面所有的内容。例如,如果一个文件夹被移动或删除,在这个文件夹里面的对象也将被通知触发相应的事件。在这种情况下,第二个参数event,其event.object将索引到这个原始的文件夹,而第一个参数将是该文件夹的子对象,并且该子对象是当前正在被处理。
发现在zope.app.container.interfaces接口的Container events被OFS.ObjectManager大量触发,这些Container events由于每一个都支持IObjectMovedEvent接口,实际处理时,需要一些技巧。事件过程涉及到oldParent, oldName,newParent和 newName这些属性所依靠的对象在哪里,它过去被调用什么,它现在的位置在哪里,它现在被调用什么等等依次问题。在一个IObjectAddedEvent中,oldParent 和 oldName 都为None,在IObjectRemovedEvent中方向是相反的,即有oldParent 和 oldName,而newParent和 newName都为None。这意味着如果你为IObjectMovedEvent预定了subscriber,该subscriber将在对象被renamed, moved, added, 或者 removed时都被调用。如果你想仅仅反应对象被实际移动才触发IObjectMovedEvent,应该在代码中显式地检查是否签署的四个变量是None。
给定通常的,以对象为中心Plone用户自然接口的环境下,object events是相对普遍的。
一些更普遍的object events(对象事件)类型是:
定义event的新类型非常简单,只需要一个标示event的接口和一个实际的类实现。
>>> from zope.interface import Interface, Attribute
>>> class INewGigEvent(Interface):
... """An event signaling that there's a new gig in town
... """
...
... band = Attribute("Name of the band")
>>> from zope.interface import implements
>>> class NewGigEvent(object):
... implements(INewGigEvent)
...
... def __init__(self, band):
... self.band = band上述代码就是一个完整的event类型,然后我们可以为这个事件类型定义一个预定者,这应当是一个简单的可调用对象,当被调用时,将把event对象作为参数传进来。 >>> from zope.component import adapter
>>> @adapter(INewGigEvent)
... def invite_friends(new_gig):
... print "Hey guys, let's go see", new_gig.band这个@adapter标识符用于标明被操纵的event类型。Event预定者被用ZCML注册:
<subscriber handler=".events.invite_friends" />如果我们不用@adapter申明,我们也可在zcml中显式地指定事件的类型,如下:
<subscriber
for=".interfaces.INewGigEvent"
handler=".events.invite_friends"
/>一旦触发该事件,所有预定该事件的预定者将被调用而执行代码,象下面样例一样简单: >>> from zope.event import notify
>>> notify(NewGigEvent("The Gypsy Sun and Rainbow Band"))
Hey guys, let's go see The Gypsy Sun and Rainbow Band这里不需要显式注册事件的类型,因为事件预定者是基于该事件对象提供的接口而找到的。这也意味着如果一个事件对象提供的接口继承自一个基本接口,并且这个基接口也有更通常的预定者,那么这些预定者也将被调用。对象事件
Zope 和 Plone 触发一些通常的事件,我们称之为对象事件,如当一个内容对象在容器中被添加、删除或者移动,或者当被首次创建、修改、拷贝时,就触发对象事件。这些事件都生成于zope.component.interfaces.IObjectEvent.
我们为对象事件注册预定者时,和其他类型的事件一样,但通常对于对象事件,我们在触发它时,往往针对特定类型的对象。也就是说我们在注册对象事件预定者时,往往针对对象类型和事件类型两个接口:
>>> class IBand(Interface):
... """A band
... """
...
... name = Attribute("The name of the band")
>>> class Band(object):
... implements(IBand)
...
... def __init__(self, name):
... self.name = name
>>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent
>>> @adapter(IBand, IObjectModifiedEvent)
... def band_changed(band, event):
... assert band == event.object # At least normally, see below
... print "Changes to the lineup in", band.name
ZCML配置:<subscriber handler=".events.band_changed" />或者,如果没有使用@adapter标识,注册如下,两个接口间用空格分开:
<subscriber
for=".interfaces.IBand
zope.lifecycleevent.interfaces.IObjectModifiedEvent"
handler=".events.band_changed"
/>对象事件触发和普通事件触发没有什么不同,但我们必须确保正确构造该对象事件的实例,以便event.object索引到正确的内容对象: >>> from zope.lifecycleevent import ObjectModifiedEvent
>>> beatles = Band("The Beatles")
>>> notify(ObjectModifiedEvent(beatles))
Changes to the lineup in The Beatles
因为我们现在依赖两个接口,这个预定者被传输进来两个对象:内容对象和事件对象。在大多数情况下,象上面样例代码中的断言一样,内容对象被传输进来作为首个参数,它和event.object应该是同一个东西。 然而,容器对象的事件会被重新分发到该容器里面所有的内容。例如,如果一个文件夹被移动或删除,在这个文件夹里面的对象也将被通知触发相应的事件。在这种情况下,第二个参数event,其event.object将索引到这个原始的文件夹,而第一个参数将是该文件夹的子对象,并且该子对象是当前正在被处理。
发现在zope.app.container.interfaces接口的Container events被OFS.ObjectManager大量触发,这些Container events由于每一个都支持IObjectMovedEvent接口,实际处理时,需要一些技巧。事件过程涉及到oldParent, oldName,newParent和 newName这些属性所依靠的对象在哪里,它过去被调用什么,它现在的位置在哪里,它现在被调用什么等等依次问题。在一个IObjectAddedEvent中,oldParent 和 oldName 都为None,在IObjectRemovedEvent中方向是相反的,即有oldParent 和 oldName,而newParent和 newName都为None。这意味着如果你为IObjectMovedEvent预定了subscriber,该subscriber将在对象被renamed, moved, added, 或者 removed时都被调用。如果你想仅仅反应对象被实际移动才触发IObjectMovedEvent,应该在代码中显式地检查是否签署的四个变量是None。
给定通常的,以对象为中心Plone用户自然接口的环境下,object events是相对普遍的。
一些更普遍的object events(对象事件)类型是:
- 上述的在zope.app.container.interfaces接口的container events
- life-cycle事件IObjectCreatedEvent 和 IObjectModifiedEvent
- 来自zope.lifecycleevent.interfaces接口,当对象被首次创建并后序被修改时从视图代码触发的,在Products.Archetypes.interfaces接口包括的 Archetypes-specific events
- 继承自IObjectModifiedEvent的IObjectInitializedEvent 和 IObjectEditedEvent。这些事件实际上是Archetypes objects被创建在ZODB中,但还没有实际的内容数据被写入时。
- Workflow events like Products.CMFCore.interfaces
- IActionSucceededEvent 和更低级别的 Products.DCWorkflow.IAfterTransitionEvent