[Product-Developers] Re: Using plone.portlets to define portlets by interface, not by type
Tim Hicks
tim at sitefusion.co.uk
Sun Feb 3 17:47:25 UTC 2008
Hi Martin,
(Re-awakening an old thread...)
Thanks for your reply before. I'm afraid I'm only just getting back to
this issue...
Martin Aspeli wrote:
> Tim Hicks wrote:
>> Hi (Martin),
>>
>> Is it possible to assign a selection of portlets to a specific
>> interface, rather than a specific content type? That is, can I do
>> something like the following, where INTERFACE_CATEGORY has been
>> substituted in for CONTENT_TYPE_CATEGORY?
>>
>>
>> from plone.portlets.constants import INTERFACE_CATEGORY
>> left_column = getUtility(IPortletManager, name="plone.leftcolumn")
>> left_category = left_column[INTERFACE_CATEGORY]
>> left_portlets = left_category.get('Weblog', None)
>> # It may be that it hasn't been created yet, so just to be safe:
>> if left_portlets is None:
>> left_category[my_interfaces_dotted_name] =
>> PortletAssignmentMapping()
>> left_portlets = left_category[my_interfaces_dotted_name]
>> for name, assignment, kwargs in DEFAULT_LEFT_PORTLETS:
>> if not left_portlets.has_key(name):
>> left_portlets[name] = assignment(**kwargs)
>
> An IPortletRetriever is used to pick the portlets to be returned. It
> asks an IPortletContext what the "current" cateogories and their values
> are - so, we may return a tuple like ((CONTENT_TYPE_CATEGORY,
> 'Document',), (GROUP_CATEGORY, 'MyGroup',), (GROUP_CATEGORY,
> 'MyOtherGroup')). It then uses the category + value (in the order given)
> to look up global portlet assignments in an IPortletManager.
Ok, so I've tried to override the standard IPortletContext with my own
that additionally returns an 'interface_category' category. It looks
(approximately) like this:
class WeblogAwarePortletContext(ContentContext):
"""
"""
implements(IPortletContext)
adapts(Interface, ISiteRoot)
def globalPortletCategories(self, placeless=False):
cats = super(ContentContext,
self).globalPortletCategories(placeless)
ifaces = self._getInterfaces()
for iface in ifaces:
cats.append(INTERFACE_CATEGORY, iface.__identifier__)
def _getInterfaces(self):
if IWeblog.providedBy(self.context):
return [IWeblog,]
if IWeblogEnhanced.providedBy(self.context):
return [IWeblogEnhanced,]
return [Interface,]
In my overrides.zcml file (which is explicitly invoked from an
overrides.zcml in my Products.QuillsEnabled package), I have the following:
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone">
<!-- Set up the portlet context -->
<adapter factory=".context.WeblogAwarePortletContext" />
</configure>
However, when I try to assign some specific portlets to this category, I
get a KeyError on my value for INTERFACE_CATEGORY (i.e.
'interface_category'). Specifically, I try:
def weblogPortletSetup(portal,
out,
ifaces=[IWeblog, IWeblogEnhanced]):
left_column = getUtility(IPortletManager, name="plone.leftcolumn")
left_category = left_column[INTERFACE_CATEGORY]
... and get the KeyError on that last line.
One clue about why this isn't working is that adding an "import pdb;
pdb.set_trace()" to the first line of my globalPortletCategories method
reveals that it never gets called. So, it looks like I haven't got
something registered properly. Any clues?
> So yes - you can define new categories, and you can use the dict-like
> semantics of an IPortletManager to store them. The README.txt in
> plone.portlets (not plone.app.portlets) will tell you more about how
> this works.
Ok.
> Another thing you may want to think about is to use a more global
> portlet assignment category, but to register different
> IPortletRenderer's for different context interfaces. That way, you can
> use the same assignment but vary the rendering by interface (including
> local markers, of course).
IIUC, this is the approach that I am taking. I trying to register a
general IPortletContext that gives a new 'interface_category' category.
Then I use that same IPortletContext to decide which interfaces are
relevant for the portlet lookup (i.e. with my _getInterfaces method).
I'm not sure if this is really the best way of approaching this, however.
Would it make sene for the core plone.app.portlets code to provide an
INTERFACE_CATEGORY ootb? That way, there could be a simple api for
registering portlets per interface. Something like:
from plone.app.portlets import registerPortletForInterface
registerPortletForInterface(a_portlet_assignment, IMyInterface)
Based on those registrations, code in plone.app.portlets would then
return a list of portlet assignments for each interface implemented by
the context object.
Just a thought.
Tim
More information about the Product-Developers
mailing list