Local sites in Five
===================

Intro
-----

Zope 3 has a concept of local sites and site managers.  They allow one
to locally override component registrations and have components and
their configuration be persisted in the ZODB as well as managed
through the web interface.

By default, Zope 3 has a global site which is configured through ZCML.
It provides the fallback for all component look-up.  Local sites are
typically set during traversal, when the traverser encounters an
``ISite`` object.  The last encountered ``ISite`` wins.  Component
look-up will cascade through all the sites in the hierarchy and fall
back to the global site where it can finally fail.

Five also supports local sites, however by default only local
utilities.  Local adapters, such as ZODB-based views, could be
supported with a custom implementation of the local site manager and
local adapter registry.  This is not the focus of local sites in Five,
though.


Turning possible sites into sites
---------------------------------

Five uses the same technique as Zope 3 for determining local sites:
sites are found during URL traversal.  However, since the Zope 2
ZPublisher doesn't emit the necessary events by default, Five needs to
set a ``BeforeTraverse`` hook on site objects.

Setting this hook needs to be done an object-per-object basis and can
be performed through the ``manage_site.html`` browser page.  This view
operates on ``IPossibleSite`` objects (in other words, objects that
*can* be sites but aren't yet).  It sets the traversal hook on the
object and then marks it with the ``ISite`` interface to indicate that
it is a real site now, not just a possible site.

Note that unlike the Zope 3 equivalent of this view, it does not set
the site manager to site; it is assumed that the site already knows
how to get its site manager.

Also note that in order for the view to work, the object's class needs
to be Five-traversable, e.g. with the following ZCML statement:

   <five:traversable class=".module.MyClass" />


Custom site implementations
---------------------------

Anything can be a site, there are no restrictions (sites don't have to
be folders, for examples).  Sites can also be nested.  For all the
Component Architecture cares, every object in your URL graph could be
a site.

The only requirement are two interfaces:

``IPossibleSite``

    Objects that can potentially be turned into a site need to provide
    this interface.  That requires them to have a ``setSiteManager()``
    and ``getSiteManager()`` method for setting and getting the local
    site manager of that site.  The site manager is the registry that
    takes care of local component look-up.

``IFiveSiteManager``

    This interface is a slight extension of the ``IServiceService`` or
    ``ISiteManager`` interface, respectively (the former in Zope X3
    3.0, the latter in later versions).  It defines the API of a local
    site manager that is to be used in a Five environment.  The site's
    ``getSiteManager()`` method should return an object providing this
    interface.


Five's default site manager
----------------------------

If you want to instantly make your custom class an ``IPossibleSite``
implementation, you can use a default mix-in class from Five, e.g.::

  class MySite(OFS.Folder, Products.Five.site.localsite.FiveSite):
      pass

This default implementation of ``IPossibleSite`` features a site
manager implementation that knows how to register and look-up local
utilities.  It does so by adapting the site to
``IFiveUtilityRegistry``.

The default adapter for this local utility registry simply stores the
utilities in a standard OFS Folder on called ``utilities`` on the site
object.  You probably want to exchange that simple behaviour with
something that works better in your application.  You can do so by
plugging in your own utility registry adapter, e.g.::

  <adapter for=".interfaces.IMySite"
           provides="Products.Five.site.interfaces.IFiveUtilityRegistry"
           fatory=".module.MyUtilityRegistry" />

All this implementation needs to do is comply with the
``IFiveUtilityRegistry`` interface, which essentially means the
standard utility look-up methods like ``queryUtility()``,
``getUtilitiesFor()``, etc.


Turning existing classes into possible sites
--------------------------------------------

If you cannot or do not want to modify existing classes to mix in the
``FiveSite`` class, you can also use a structured monkey patch via
ZCML::

   <five:localsite class=".module.MyClass" />

This makes ``MyClass`` an ``IPossibleSite`` and sticks ``FiveSite``'s
``getSiteManager()`` and ``setSiteManager()`` methods on the class as
well.  You can also tell it to use a different site implementation's
methods for the monkey patch::

   <five:localsite class=".module.MyClass"
                   site_class=".module.MySiteImpl" />

Just make sure that this class implements ``IPossibleSite``.
