diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-06-24 03:20:56 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-06-24 03:20:56 +0000 |
| commit | 62cd249385317b79a68916e5d982d7cc0c7960da (patch) | |
| tree | b9bf314a32470b6ec0b6b168b708bf93215ece2e | |
| parent | 3d38927015524fb7e8c582894912d74392bc25fa (diff) | |
| download | pyramid-62cd249385317b79a68916e5d982d7cc0c7960da.tar.gz pyramid-62cd249385317b79a68916e5d982d7cc0c7960da.tar.bz2 pyramid-62cd249385317b79a68916e5d982d7cc0c7960da.zip | |
Add (painful) explanation of weak-binding route view context registrations.
| -rw-r--r-- | docs/glossary.rst | 7 | ||||
| -rw-r--r-- | docs/narr/hybrid.rst | 159 |
2 files changed, 118 insertions, 48 deletions
diff --git a/docs/glossary.rst b/docs/glossary.rst index 319483466..217c70098 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -271,6 +271,13 @@ Glossary registry`. You can also use decorators to configure views in :mod:`repoze.bfg`; see :ref:`mapping_views_to_urls_using_a_decorator_section`. + Zope Component Architecture + The `Zope Component Architecture + <http://www.muthukadan.net/docs/zca.html>`_ (aka ZCA) is a system + which allows for application pluggability and complex dispatching + based on objects which implement an :term:`interface`. + :mod:`repoze.bfg` uses the ZCA "under the hood" to perform view + dispatching and other application configuration tasks. ReStructuredText A `plain text format <http://docutils.sourceforge.net/rst.html>`_ that is the defacto standard for descriptive text shipped in diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst index 66c1b55fc..2fe7a65ed 100644 --- a/docs/narr/hybrid.rst +++ b/docs/narr/hybrid.rst @@ -22,7 +22,10 @@ matching, 2) root factories and 3) the traversal algorithm, and the interactions between all of them. Therefore, use of this pattern is not recommended unless you *really* need to use it. -It's useful to read :ref:`router_chapter` to get a more holistic +This is a advanced topic that has non-trivial corner cases; you may +need to understand more deeply how :mod:`repoze.bfg` works to +understand the concepts discussed in this chapter. To that end, it's +useful to read :ref:`router_chapter` to get a more holistic understanding of what's happening "under the hood" to use this feature. @@ -249,6 +252,113 @@ Corner Cases A number of corner case "gotchas" exist when using a hybrid application. Let's see what they are. +.. _globalviews_corner_case: + +"Global" Views Match Any Route When A More Specific View Doesn't +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note that views that *don't* mention a ``route_name`` will *also* +match when *any* route matches. For example, the "bazbuz" view below +will be found if the route named "abc" below is matched. + +.. code-block:: xml + + <route + path="/abc/*traverse" + name="abc" + view=".views.abc" + /> + + <view + name="bazbuz" + view=".views.bazbuz" + /> + +To override the behavior of the "bazbuz" view when this route matches, +use an additional view that mentions the route name explicitly. + +.. code-block:: xml + + <route + path="/abc/*traverse" + name="abc" + view=".views.abc" + /> + + <view + name="bazbuz" + view=".views.bazbuz" + /> + + <view + name="bazbuz" + route_name="abc" + view=".views.bazbuz2" + /> + +In the above setup, when no route matches, and traversal finds the +view name to be "bazbuz", the ``.views.bazbuz`` view will be used. +However, if the "abc" route matches, and traversal finds the view name +to be "bazbuz", the ``.views.bazbuz2`` view will be used. + +``context`` Type (aka "for") Registrations Bind More Tightly Than ``request`` Type Registrations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This corner case is only interesting if you are using a hybrid +application and you believe the "wrong" view is being called for a +given request. + +This explanation requires a little "inside baseball" knowledge of how +:mod:`repoze.bfg` works. :mod:`repoze.bfg` uses the :term:`Zope +Component Architecture` under the hood to dispatch a request to a +:term:`view`. In Zope Component Architecture-speak, a view is an +"multi adapter" registered for a :term:`context` type and a +:term:`request` type as well as a particular :term:`view name`. When +a request is generated and a context is found by the :mod:`repoze.bfg` +:term:`router`, it uses these two values, along with the :term:`view +name` to try to locate a view callable. + +A view is registered for a ``route`` either as its default view via +the ``view=`` attribute of a ``route`` declaration in ZCML *or* as a +standalone ``<view>`` declaration (or via the ``@bfg_route`` +decorator) which has a ``route_name`` that matches the route's name). +At startup time, when such a registration is encountered, the view is +registered for the ``context`` type ``None`` (meaning *any* context) +and a *special* request type which is dynamically generated. This +request type also derives from a "base" request type, which is what +allows it to match against views defined without a route name (see +:ref:`globalviews_corner_case`). + +When a request URL matches a ``<route>`` path, the special request +type interface mentioned in the previous paragraph is attached to the +``request`` object as it is created. The *root* found by the router +is based on either the route's ``factory`` (or the default root +factory if no ``factory`` is mentioned in the ``<route>`` +declaration). This root is eventually resolved to a ``context`` via +:term:`traversal`. This ``context`` will either have some particular +interface, or it won't, depending on the result of traversal. + +Given how view dispatch works, since the registration made "under the +hood" for views that match a route use the (very weakly binding) +``None`` value as the context value's interface, if the context that +is found has a specific interface, and a global view statement is +registered against this interface as its context interface, it's +likely that the *global* view will match *before* the view that is +attached to the route unless the ``view_for`` attribute is used on the +``route`` registration to match the "correct" interface first (because +then both the request type and the context type are "more specific" +for the view registration). + +What it all boils down to is: if a request that matches a route +resolves to a view you don't expect it to, use the ``view_for`` +attribute of the ``route`` statement (*or* the ``for`` attribute of +the ZCML statement that also has a ``route_name`` *or* the equivalent +``for_`` parameter to the ``@bfg_view`` decorator that also has a +``route_name`` parameter) to name the specific context interface you +want the route-related view to match. + +Yes, that was as painful for me to write as it was for you to read. + Registering a Default View for a Route That has a ``view`` attribute ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -342,53 +452,6 @@ you must the special ``*traverse`` token to the route's "path"., e.g.: route_name="abc" /> -"Global" Views Match Any Route When A More Specific View Doesn't -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Note that views that *don't* mention a ``route_name`` will *also* -match when *any* route matches. For example, the "bazbuz" view below -will be found if the route named "abc" below is matched. - -.. code-block:: xml - - <route - path="/abc/*traverse" - name="abc" - view=".views.abc" - /> - - <view - name="bazbuz" - view=".views.bazbuz" - /> - -To override the behavior of the "bazbuz" view when this route matches, -use an additional view that mentions the route name explicitly. - -.. code-block:: xml - - <route - path="/abc/*traverse" - name="abc" - view=".views.abc" - /> - - <view - name="bazbuz" - view=".views.bazbuz" - /> - - <view - name="bazbuz" - route_name="abc" - view=".views.bazbuz2" - /> - -In the above setup, when no route matches, and traversal finds the -view name to be "bazbuz", the ``.views.bazbuz`` view will be used. -However, if the "abc" route matches, and traversal finds the view name -to be "bazbuz", the ``.views.bazbuz2`` view will be used. - Route Ordering ~~~~~~~~~~~~~~ |
