Event handlers¶
Adding custom event handlers for your type
So far, we have mainly been concerned with content types’ schemata and forms created from these. However, we often want to add more dynamic functionality, reacting when something happens to objects of our type. In Zope, that usually means writing event subscribers.
Zope’s event model is synchronous. When an event is broadcast (via the
notify()
function from the zope.event package), for example from the
save
action of an add form, all registered event handlers will be
called. There is no guarantee of which order the event handlers will be
called in, however.
Each event is described by an interface, and will typically carry some
information about the event. Some events are known as object events,
and provide zope.component.interfaces.IObjectEvent
. These have an
object
attribute giving access to the (content) object that the event
relates to. Object events allow event handlers to be registered for a
specific type of object as well as a specific type of event.
Some of the most commonly used event types in Plone are shown below. They are all object events.
zope.lifecycleevent.interfaces.IObjectCreatedEvent
- fired by the standard add form just after an object has been created,
but before it has been added on the container. Note that it is often
easier to write a handler for
IObjectAddedEvent
(see below), because at this point the object has a proper acquisition context. zope.lifecycleevent.interfaces.IObjectModifiedEvent
- fired by the standard edit form when an object has been modified.
zope.lifecycleevent.interfaces.IObjectAddedEvent
- fired when an object has been added to its container. The container is
available as the
newParent
attribute, and the name the new item holds in the container is available asnewName
. zope.lifecycleevent.interfaces.IObjectRemovedEvent
- fired when an object has been removed from its container. The container
is available as the
oldParent
attribute, and the name the item held in the container is available asoldName
. zope.lifecycleevent.interfaces.IObjectMovedEvent
- fired when an object is added to, removed from, renamed in, or moved
between containers. This event is a super-type of
IObjectAddedEvent
andIObjectRemovedEvent
, shown above, so an event handler registered for this interface will be invoked for the ‘added’ and ‘removed’ cases as well. When an object is moved or renamed, all ofoldParent
,newParent
,oldName
andnewName
will be set. Products.CMFCore.interfaces.IActionSucceededEvent
- fired when a workflow event has completed. The
workflow
attribute holds the workflow instance involved, and theaction
attribute holds the action (transition) invoked.
Event handlers can be registered using ZCML with the <subscriber />
directive.
As an example, let’s add an event handler to the Presenter
type that
tries to find users with matching names matching the presenter id, and
send these users an email.
First, we require an additional import at the top of presenter.py
:
from Products.CMFCore.utils import getToolByName
Then, we’ll add the following event subscriber after the schema definition:
def notifyUser(presenter, event):
acl_users = getToolByName(presenter, 'acl_users')
mail_host = getToolByName(presenter, 'MailHost')
portal_url = getToolByName(presenter, 'portal_url')
portal = portal_url.getPortalObject()
sender = portal.getProperty('email_from_address')
if not sender:
return
subject = "Is this you?"
message = "A presenter called %s was added here %s" % (presenter.title, presenter.absolute_url(),)
matching_users = acl_users.searchUsers(fullname=presenter.title)
for user_info in matching_users:
email = user_info.get('email', None)
if email is not None:
mail_host.secureSend(message, email, sender, subject)
And register it in ZCML:
<subscriber
for=".presenter.IPresenter zope.lifecycleevent.interfaces.IObjectAddedEvent"
handler=".presenter.notifyUser"
/>
There are many ways to improve this rather simplistic event handler, but
it illustrates how events can be used. The first argument to
for
is an interface describing the object type. The second argument
is the event type. The arguments to the function reflects these two,
so the first argument is the IPresenter
instance and the second is an
IObjectAddedEvent
instance.