summaryrefslogtreecommitdiff
path: root/docs/narr/events.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr/events.rst')
-rw-r--r--docs/narr/events.rst119
1 files changed, 119 insertions, 0 deletions
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
new file mode 100644
index 000000000..1e69a6f7f
--- /dev/null
+++ b/docs/narr/events.rst
@@ -0,0 +1,119 @@
+.. _events_chapter:
+
+Using Events
+=============
+
+An *event* is an object broadcast by the :mod:`repoze.bfg` framework
+at particularly interesting points during the lifetime of your
+application. You don't need to use, know about, or care about events
+in order to create most :mod:`repoze.bfg` applications, but they can
+be useful when you want to do slightly advanced operations, such as
+"skinning" a site slightly differently based on, for example, the
+hostname used to reach the site.
+
+Events in :mod:`repoze.bfg` are always broadcast by the framework.
+They only become useful when you register a *subscriber*. A
+subscriber is a function that accepts a single argument named `event`:
+
+.. code-block:: python
+ :linenos:
+
+ def mysubscriber(event):
+ print event
+
+The above is a subscriber that simply prints the event to the console
+when it's called.
+
+The mere existence of a subscriber function, however, is not
+sufficient to arrange for it to be called. To arrange for the
+subscriber to be called, you'll need to change your :term:`application
+registry` by modifying your application's ``configure.zcml``. Here's
+an example of a bit of XML you can add to the ``configure.zcml`` file
+which registers the above ``mysubscriber`` function, which we assume
+lives in a ``subscribers.py`` module within your application:
+
+.. code-block:: xml
+ :linenos:
+
+ <subscriber
+ for="repoze.bfg.interfaces.INewRequest"
+ handler=".subscribers.mysubscriber"
+ />
+
+The above example means "every time the :mod:`repoze.bfg` framework
+emits an event object that supplies an ``INewRequest`` interface, call
+the ``mysubscriber`` function with the event object. As you can see,
+subscriptions are made to *interfaces*. The event object sent to a
+subscriber will always have an interface. You can use the interface
+itself to determine what attributes of the event are available.
+
+For example, if you create event listener functions in a
+``subscribers.py`` file in your application like so:
+
+.. code-block:: python
+ :linenos:
+
+ def handle_new_request(event):
+ print 'request', event.request
+
+ def handle_new_response(event):
+ print 'response', event.response
+
+You may configure these functions to be called at the appropriate
+times by adding the following to your application's ``configure.zcml``
+file:
+
+.. code-block:: xml
+ :linenos:
+
+ <subscriber
+ for="repoze.bfg.interfaces.INewRequest"
+ handler=".subscribers.handle_new_request"
+ />
+
+ <subscriber
+ for="repoze.bfg.interfaces.INewResponse"
+ handler=".subscribers.handle_new_response"
+ />
+
+This causes the functions as to be registered as event subscribers
+within the :term:`application registry` . Under this configuration,
+when the application is run, every new request and every response will
+be printed to the console. We know that ``INewRequest`` events have a
+``request`` attribute, which is a :term:`WebOb` request, because the
+interface defined at ``repoze.bfg.interfaces.INewRequest`` says it
+must. Likewise, we know that ``INewResponse`` events have a
+``response`` attribute, which is a response object constructed by your
+application, because the interface defined at
+``repoze.bfg.interfaces.INewResponse`` says it must. These particular
+interfaces are documented in the :ref:`events_module` API chapter.
+
+The *subscriber* ZCML element takes two values: ``for``, which is the
+interface the subscriber is registered for (which limits the events
+that the subscriber will receive to those specified by the interface),
+and ``handler`` which is a Python dotted-name path to the subscriber
+function.
+
+The return value of a subscriber function is ignored.
+
+Uses For Events
+---------------
+
+Here are some things that events are useful for:
+
+- Attaching different interfaces to the request to be able to
+ differentiate e.g. requests from a browser against requests from an
+ XML-RPC client within view code. To do this, you'd subscribe a
+ function to ```INewRequest``, and use the
+ ``zope.interface.alsoProvides`` function to add one or more
+ interfaces to the request object.
+
+- Post-processing all response output by subscribing to
+ ``INewResponse``, for example, modifying headers.
+
+ .. note::
+
+ Usually postprocessing requests is better handled in middleware
+ components. The ``INewResponse`` event exists purely for
+ symmetry with ``INewRequest``, really.
+