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.


Five 1.5 supports two distinct and slightly incompatible versions of
local site support. The first one, (here known as "old" sites) was 
introduced in Five 1.3 and is based on Zope 3.2s site implementation.
But the site implementation in Zope 3.2 was overly complicated, and
for 3.3 it was refactored, and Five 1.5 contains support for this new
local site support as well (known as "new" sites).

For documentation of how to use local sites, see the Zope 3.3 documentation.
This document is mostly about how the implementation of the old sites work,
and how to migrate from Five 1.3 and 1.4.


Migration from old sites to new sites
-------------------------------------

New sites are based on Zope 3.3s new site managers and persistent 
component registries. Old sites are based on specific Five implementation
of site managers, and keeps utilities in a folder called "utilities".

They are used basically the same, but they are created differently,
and also, when you look up a utility with getUtility or queryUtility, in
old sites, the utility will have an acquicition context, while in the new
sites it will not.

Setting up the site
...................

The old setup of a site was done by marking the class of the site as a
possible site with five:localsite, and then either manually through the ZMI
or programmatically through enableLocalSiteHook(site) turn it into a site.

The new setup involves calling enableSite(site) and createing and setting
a site manager. The simplest way to do this manually is to go to the 
"components.html" view of the object you want to make a site, and press the
"Make site" button. The easist way to do this programmatically, is to look 
up the "components.html" view on the site, and calling view.makeSite():

    components_view = queryMultiAdapter((self.context, self.request), 
                                         Interface, 'components.html')
    components_view.makeSite()

As any ObjectManager can be a site there is no longer any need to specially
mark the class as being a possible site.

Registering local utilities
...........................

The old usage was to get the site manager, either throgh adapting with
IFiveUtilityRegistry(site) or by calling getSiteManager(). You could then
register the utilities with sitemanager.registerUtility(interface, utility)

The new way is to call getSiteManager().registerUtility(object, provided).
Note that in the old way, the first parameter is the interface name, and 
the second the actual utility object, but in the new way, it is the other
way around.

Migrating the actual sites
..........................

Go to the object of the site, and add "manage_site.html" to the URL to open
the old site management view. There you have a button 
"Migrate to Five.component". Press it to migrate the site.

Experimental forwards compatibility
...................................

If you have software using the old sites, and software using the new sites,
there is sligthly experimental support to make software expecting new sites
to work with old sites. Nothing is promised with this, as it is largely
untested. The best thing to do is without a doubt to convert your old site
software and your old sites to use new sites.



Old site implementation details
===============================

The rest of this document documents the details of the old site implementation.
Everything from here on concerns only the old implementation and is of mainly
hysterical interest.

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.


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``.
