While developing a small application with a lot of vocabularies I found a pattern how to use registry-values as a vocabulary. I'd like to know if you think this is a good idea.
It is based on https://training.plone.org/5/mastering-plone/registry.html#vocabularies
Basically it goes like this:
Create a controlpanel that stores settings in the registry as usual in controlpanel.py
:
# -*- coding: utf-8 -*-
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
from plone.app.registry.browser.controlpanel import RegistryEditForm
from plone.z3cform import layout
from zope import schema
from zope.interface import Interface
class IProjectControlPanel(Interface):
foo = schema.Tuple(
title=u'Foo',
default=(
u'One',
u'Two',
),
missing_value=None,
required=False,
value_type=schema.TextLine(),
)
bar = schema.Tuple(
title=u'Bar',
default=(
u'Three',
u'Four',
),
missing_value=None,
required=False,
value_type=schema.TextLine(),
)
class ProjectControlPanelForm(RegistryEditForm):
schema = IProjectControlPanel
schema_prefix = 'project'
label = u'Project Settings'
ProjectControlPanelView = layout.wrap_form(
ProjectControlPanelForm, ControlPanelFormWrapper)
Register that in registry.xml
:
<records interface="my.project.browser.controlpanel.IProjectControlPanel"
prefix="project" />
Now the trick. Instead of having many vocabularies that di the same with different values I reuse the same factory and get the registry-value in question from the stack. Register named vocabularies with the same name as the registry-entry and point to the same factory:
<utility
name="project.foo"
component="my.project.vocabularies.RegistryValueVocabularyFactory" />
<utility
name="project.bar"
component="my.project.vocabularies.RegistryValueVocabularyFactory" />
In vocabularies.py
get the name and reuse it to get the registry-value:
# -*- coding: utf-8 -*-
from inspect import currentframe
from plone import api
from plone.app.vocabularies.terms import safe_simplevocabulary_from_values
from zope.interface import provider
from zope.schema.interfaces import IVocabularyFactory
@provider(IVocabularyFactory)
def RegistryValueVocabularyFactory(context):
# get the name of this utility by inspecting the previous stack
name = currentframe().f_back.f_locals['name']
values = api.portal.get_registry_record(name)
return safe_simplevocabulary_from_values(values)
Now you can use it in your schema:
class ISomeType(model.Schema):
foo = schema.Choice(
title=u'Foo',
vocabulary='project.foo',
required=False,
)
bar = schema.Choice(
title=u'Bar',
vocabulary='project.bar',
required=False,
)