Tutorial
Return to main page
Date: 01/18/10 at 18:05:54
More ZCA Integration
Author: chrismDate: 01/18/10 at 18:05:54
See below...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | > Since you're working in this area, I wonder if you could clarify
> > something for me. In my application, I registered a utility using a BFG
> > ZCML directive, but when I tried to use the utility, I found that no
> > utilities were registered at all. I solved the problem by adding a call
> > to hook_zca() in my run.py, mimicking some code I found in BFG. So the
> > end of my run.app() now looks like this:
> >
> > config = Configurator(settings=settings, root_factory=root_factory)
> > config.hook_zca()
> > config.begin()
> > config.load_zcml(zcml_file)
> > config.end()
> > return config.make_wsgi_app()
> >
> > Is this a sensible solution?
I think so. The way it works is this:
- At startup, the component registry associated with the Configurator is
populated. Each BFG app uses its own component registry. If a registry
is not passed to the configurator constructor, one is created.
- During a request, the application component registry is "made current".
This means calls to "r.b.threadlocal.get_current_registry()" in the
thread handling the request will return the component registry.
- BFG itself always uses "get_current_registry()" in places that
it doesn't "naturally" have access to the registry.
- App developers can use get_current_registry() to get the registry
and thus get access to utilities and such, e.g.
get_current_registry().getUtility(...)
So far I haven't mentioned anything about the "ZCA global" APIs like
getSiteManager, getUtility, etc. Using the ZCA global API to get at data in a
BFG registry is actually not documented within the BFG documentation. It's
sort of a hidden feature that doing so is even possible.
Without special treatment, the ZCA global APIs will always return the global
ZCA registry (the one in z.component.globalregistry.base). To make them start
returning the "current" BFG registry, as you found, calling config.hook_zca()
is required. config.hook_zca() does this under the hood:
from zope.component import getSiteManager
from repoze.bfg.threadlocal import get_current_registry
getSiteManager.sethook(get_current_registry)
This causes the ZCA global API to start using the BFG application registry in
threads which are running a BFG request.
There are three other options:
- You can disuse the ZCA global API and use get_current_registry()
instead.
- You disuse both the ZCA global API and get_current_registry() and rely
on getting to the registry via "request.registry" (in view code).
- You can tell your BFG app to use the ZCA global registry at startup time:
from zope.component import getGlobalSiteManager
config = Configurator(registry=getGlobalSiteManager(), settings=settings,
root_factory=root_factory)
config.setup_registry()
config.begin()
config.load_zcml(zcml_file)
config.end()
return config.make_wsgi_app()
The last option means that the configurator will populate and use the ZCA
global registry rather than creating a new application-specific registry; since
by default the ZCA global API will use this registry, things will work as you
might expect a Zope app to when you use the global ZCA API.
|