Pipelined Event Subscription ============================ The traditional Zope3 event subscription model provides no guarantees of ordering in the delivery of event to subscribers. This package provides an extension to allow the site manager to arrange a set of subscribers for a particular event in order. Use Cases +++++++++ Site Integrator Imposes Site Identity ------------------------------------- An integrator can take the output rendered by the CMS and impose corporate standards / logos, etc., without modifying the skins of the CMS. She does this by registering a pipeline for the IEndRequestEvent emitted by the publication object, and transform the response body. Each transformation would be a filter in an event pipeline. Let's create the pipeline filters. The first one just converts the response body to a DOM: >>> def domify(event, state): ... # Add a 'dom' attribute to the response, using minidom. ... from xml.dom.minidom import parseString ... response = event.request.response ... state.dom = parseString(response.body) The second filter adds a copyright statement at the very end of the body of the response: >>> def addCopyright(event, state): ... # Add a copyright paragraph at the end of the response's body. ... # N.B.: expects DOM already parsed. ... from xml.dom.minidom import Element, Text ... dom = state.dom ... graph = Element(tagName='p') ... text = Text() ... text.data = 'Copyright 2005 Example Company' ... graph.appendChild(text) ... body = dom.getElementsByTagName('body')[0] ... body.appendChild(graph) The last filter re-stringifies the DOM and replaces the response body. >>> def replaceBodyFromDOM(event, state): ... response = event.request.response ... dom = state.dom ... response.setBody(dom.toxml()) Now, construct a pipeline from the three filters: >>> filters = (domify, addCopyright, replaceBodyFromDOM) >>> from pipelines.pipeline import Pipeline >>> pipeline = Pipeline(filters) Next, synthesize a request / response for testing the event delivery: >>> class FauxRequest: ... pass >>> class FauxResponse: ... body = '' ... def setBody(self, value): ... self.body = value >>> request = FauxRequest() >>> response = request.response = FauxResponse() Check that the pipeline works when handed directly to the pipeline: >>> from zope.app.publication.interfaces import EndRequestEvent >>> event = EndRequestEvent(None, request) >>> response.setBody("
") >>> pipeline.processFilters(event) and None # don't care about result >>> print response.bodyCopyright 2005 Example Company
Then, check that the pipeline works cleanly as a subscriber to the EndRequestEvent. >>> from zope.app.zapi import getGlobalSiteManager >>> from zope.app.publication.interfaces import IEndRequestEvent >>> gsm = getGlobalSiteManager() >>> gsm.subscribe([IEndRequestEvent], None, pipeline) Then, publish the "done publishing" event: >>> from zope.event import notify >>> response.setBody("") >>> notify(event) Finally, verify that our pipeline ran in response to the event: >>> print response.bodyCopyright 2005 Example Company
User Requests Transform of a Document to PDF -------------------------------------------- While viewing a document, a user requests a PDF version of the document. The 'asPDF' view fetches the "raw" content of the document, and then publishes an IContentRendering event. The transforms which convert the raw content to PDF are defined as a pipeline, which incrementally converts the content, e.g. from restructured text to HTML to PDF. In this mode, rather than registering the pipeline as an event subscriber, we register it as a named utility implementing IPipeline. Application code then looks it up as a utility in order to call it.