Subscribers (event handlers)#

A subscriber is a callable object that takes one argument, an object that we call the event.

Events are objects that represent something happening in a system. They are used to extend processing by providing processing plug points.

A notification alerts subscribers that an event has occurred.

The Zope Component Architecture's zope.event package is used to manage subscribable events in Plone.

The Plone event system has some notable characteristics:

  • It's simple.

  • The calling order of subscribers is random. You can't set the order in which event handlers are called.

  • Events can't be cancelled. All handlers will always get the event.

  • Event handlers can't have return values.

  • Exceptions raised in an event handler will interrupt the request processing.

Register an event handler#

Plone events can be scoped:

  • globally (no scope)

  • per content type

  • per behavior or marker interface

Register an event handler on content type creation#

The following example demonstrates how to register an event handler when a content type is created.

In your .product/your/product/configure.zcml insert the following code.

1<subscriber
2    for=".interfaces.IMyContentTypeClass
3         zope.lifecycleevent.IObjectCreatedEvent"
4    handler=".your_python_file.your_method"
5    />

The second line defines to which interface you want to bind the execution of your code. Here, the event handler code will only be executed if the object is a content type providing the interface .interfaces.IMyContentTypeClass. If you want this to be interface agnostic, insert an asterix * as a wildcard instead.

The third line defines the event on which this should happen, which is IObjectCreatedEvent. For more available possible events to use as a trigger, see subscribers-event-handlers.

The fourth line gives the path to the callable function to be executed.

Create your .product/your/product/your_python_file.py and insert the following code.

def your_subscriber(object, event):
    # do something with your created content type

Subscribe to an event using ZCML#

Subscribe to a global event using ZCML by inserting the following code in your .product/your/product/configure.zcml.

<subscriber
    for="Products.PlonePAS.events.UserLoggedOutEvent"
    handler=".smartcard.clear_extra_cookies_on_logout"
    />

For this event, the Python code in smartcard.py would be the following.

def clear_extra_cookies_on_logout(event):
    # What event contains depends on the
    # triggerer of the event and event class
    request = event.object.REQUEST

The following example for a custom event subscribes content types to all IMyEvents when fired by IMyObject.

<subscriber
    for=".interfaces.IMyObject
         .interfaces.IMyEvent"
    handler=".content.MyObject.myEventHandler"
    />

The following example shows how to subscribe a content type to the life cycle event.

<subscriber
    zcml:condition="installed zope.lifecycleevent"
    for=".interfaces.ISitsPatient
         zope.lifecycleevent.IObjectModifiedEvent"
    handler=".content.SitsPatient.objectModified"
    />

Fire an event#

Use zope.event.notify() to fire event objects to their subscribers.

The following code shows how to fire an event in unit tests.

import zope.event
from plone.postpublicationhook.event import AfterPublicationEvent

event = AfterPublicationEvent(self.portal, self.portal.REQUEST)
zope.event.notify(event)

Event types#

Plone has the following types of events.

Creation events#

zope.lifecycleevent.IObjectCreatedEvent is fired for all Zope-ish objects when they are created, or copied via IObjectCopiedEvent. They don't have to be content objects.

Modified events#

zope.lifecycleevent.IObjectModifiedEvent is called for creation stage events as well, unlike the previous event type.

Delete events#

Delete events can be fired several times for the same object. Some delete event transactions are rolled back.

Copy events#

zope.lifecycleevent.IObjectCopiedEvent is triggered when an object is copied. It will also fire IObjectCreatedEvent event code.

Workflow events#

Products.DCWorkflow.interfaces.IBeforeTransitionEvent is triggered before a workflow transition is executed.

Products.DCWorkflow.interfaces.IAfterTransitionEvent is triggered after a workflow transition has been executed.

The DCWorkflow events are low-level events that can tell you a lot about the previous and current states.

Products.CMFCore.interfaces.IActionSucceededEvent is a higher level event that is more commonly used to react after a workflow action has completed.

Zope startup events#

zope.processlifetime.IProcessStarting is triggered after the component registry has been loaded and Zope is starting up.

zope.processlifetime.IDatabaseOpened is triggered after the main ZODB database has been opened.