Events

Description

How to add event hooks to your Plone code to perform actions when something happens on a Plone site.

Introduction

This document briefly discusses event handling using the zope.event module. The Zope Component Architecture's zope.event package is used to manage subscribeable events in Plone.

Some of the notable characteristics of the Plone event system are:

  • it is simple;
  • subscriber calling order is not modifiable — you cannot set the order in which event handlers are called;
  • events cannot be cancelled — all handlers will always get the event;
  • event handlers cannot have return values;
  • exceptions raised in an event handler will interrupt the request processing.

For more information, see:

Registering an event handler

Note

Starting Plone 4, using grok method is recommended as it is simpler

Subscribing using the grok API

Example subscription which subscribes add and edit events for an content item type:

from five import grok
from Products.Archetypes.interfaces import IObjectEditedEvent, IObjectInitializedEvent

    class ORAResearcher(folder.ATFolder, orabase.ORABase, ResearcherMixin):
        """A Researcher synchronized from ORA.
        """
        implements(IORAResearcher, IResearcher)

        meta_type = "ORAResearcher"
        schema = ORAResearcherSchema


    # Callbacks for both add and edit events

    @grok.subscribe(ORAResearcher, IObjectEditedEvent)
    def object_edited(context, event):
        orabase.object_edited(context, event)

    @grok.subscribe(ORAResearcher, IObjectInitializedEvent)
    def object_added(context, event):
        orabase.object_added(context, event)

Example subscription which subscribes events without context:

# Really old stuff
from ZPublisher.interfaces import IPubStart

# Modern stuff
from five import grok

@grok.subscribe(IPubStart)
def check_redirect(e):
    """
    Check if we have a custom redirect script in Zope application server root.

For more information, see:

Subscribing using ZCML

Custom event example:

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

Life cycle events example:

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

Subscribing using Python

The following subscription is valid through the process life cycle. In unit tests, it is important to clear test event handlers between the test steps.

Example:

import zope.component

def my_event_handler(context, event):
    """
    @param context: Zope object for which the event was fired for. Usually this is a Plone content object.

    @param event: Subclass of event.
    """
    pass

gsm = zope.component.getGlobalSiteManager()
gsm.registerHandler(my_event_handler, (IMyObject,IMyEvent))

Firing an event

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

Example of 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

Creation events

Products.Archetypes.interfaces.IObjectInitializedEvent
is fired for an Archetypes-based object when it's being initialised; i.e. when it's being populated for the first time.
Products.Archetypes.interfaces.IWebDAVObjectInitializedEvent
is fired for an Archetypes-based object when it's being initialised via WebDAV.
zope.lifecycleevent.IObjectCreatedEvent
is fired for all Zopeish objects when they are being created (they don't necessarily need to be content objects).

Warning

Archetypes and Zope 3 events might not be compatible with each other. Please see links below.

Other resources:

Modified events

Two different content event types are available and might work differently depending on your scenario:

Products.Archetypes.interfaces.IObjectEditedEvent
called for Archetypes-based objects that are not in the creation stage any more.

Note

Products.Archetypes.interfaces.IObjectEditedEvent is fired after reindexObject() is called. If you manipulate your content object in a handler for this event, you need to manually reindex new values, or the changes will not be reflected in the portal_catalog.

zope.lifecycleevent.IObjectModifiedEvent
called for creation-stage events as well, unlike the previous event type.
Products.Archetypes.interfaces.IWebDAVObjectEditedEvent
called for Archetypes-based objects when they are being edited via WebDAV.
Products.Archetypes.interfaces.IEditBegunEvent
called for Archetypes-based objects when an edit operation is begun.
Products.Archetypes.interfaces.IEditCancelledEvent
called for Archetypes-based objects when an edit operation is cancelled.

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.

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
this 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 component registry has been loaded and Zope is starting up.
zope.processlifetime.IDatabaseOpened
is triggered after the main ZODB database has been opened.



Edit this document

The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.

  1. Go to Events on GitHub.
  2. Press Fork and edit this file button.
  3. Edit file contents using GitHub's text editor in your web browserm
  4. Fill in the Commit message text box at the end of the page telling why you did the changes. Press Propose file change button next to it when done.
  5. On Send a pull request page you don't need to fill in text anymore. Just press Send pull request button.
  6. Your changes are now queued for review under project's Pull requests tab on Github.

For basic information about updating this manual and Sphinx format please see Writing and updating the manual guide.