I suspect trying to get from content class is a trap: IEvent.implementedBy(type_class) assumes that the FTI is using something other than the default class (at least for Dexterity). Won't work for behavior-provided events, quite possibly. Better to look at the main interface and and behaviors configured on the FTI than trying to get a content implementation class from it.
we want to construct a dynamic list to replace the functionality provided in the past by portal_calendar:
we are thinking on using a catalog query we already have, to create a list of object providing the IEvent interface and then reduce that list to get all different type of portal types present on it.
Seems reasonable to query object_provides index, then get unique set of portal_type values from brains, if you memoize it. OTOH, not caching this is costly, and invalidation here is a pain: what happens when someone adds the first content item of a type that happens to be event-ish, and your cached list doesn't include its portal_type?
Is this Archetypes or Dexterity? If just Dexterity types plus built-in Event type on Plone 4, everything you need is likely in the FTI without resorting to walking your content or the catalog.
that's exactly our problem now: how do discover which IEvent interface to use, the one from ATContentTypes of the one from plone.event
it must work in any of the following cases: vanilla Plone 4; Plone 4 with plone.app.contenttypes installed; vanilla Plone 5.
you can always use the catalog counter as a key for your cache to solve that kind of issues:
from plone.memoize import ram
def _catalog_counter_cachekey(method, self):
"""Return a cachekey based on catalog updates."""
catalog = api.portal.get_tool('portal_catalog')
return str(catalog.getCounter())
@ram.cache(_catalog_counter_cachekey)
def your_expensive_method(self):
# do expensive things
If you have a site that you know that no instance is marked with a behavior that its type is not [1], you can also get this just by looking at the Dexterity FTI 'schema' and 'behaviors' attributes, without ever resorting to a catalog query [2].
[1] (per-instance behaviors are uncommon, though possible). E.g. if you have a scenario where you have a page that is also an event.
[2] I have no idea what happens when/if tiles overthrow content types for things like this.
from plone.dexterity.utils import resolveDottedName
event_types = [type.klass for type in api.portal.get_tool(name='portal_types').values() if hasattr(type, 'klass') and IEvent.implementedBy(resolveDottedName(type.klass))]