2

There is a need to extend memberdata on Plone 4 with certain schema and at the same time provide an efficient (that is, much better than linear) search among those profiles.

collective.examples.userdata seems to be an example on how to make userdata The Right Way, but what about searches? Are there any efficient search solutions, for example, using the catalog?

There is such thing as membrane, which can map users to content, but uses Archetypes and quite old a product (maybe, my impression is wrong).

Still, for example, mapping userdata to Dexterity type instances could be fine.

The question is, is there any ready code out there or custom solution will be needed?

Roman Susi
  • 4,135
  • 2
  • 32
  • 47

2 Answers2

1

No, the only ready solution out there, as you said, is membrane. But IMO it's a complex and specific product so I don't think you really need it. To reach your goal, you'll need a bit of development. More or less the way would be:

Giacomo Spettoli
  • 4,476
  • 1
  • 16
  • 24
  • Link #2 is really the core of the problem, unfortunately it no longer works. Can you provide an updated link? I found the following useful, but in my opinion this document is too broad -- http://svn.plone.org/svn/plone/plone.indexer/trunk/plone/indexer/README.txt – Alex Volkov Oct 03 '14 at 22:39
0

This is an overview (not detailed howto) of an implementation:

Catalog tool done similarly to the reference_catalog from Archetypes. The most essential parts:

from Products.ZCatalog.ZCatalog import ZCatalog
class MemberdataCatalog(UniqueObject, ZCatalog):
    implements(IMemberdataCatalog)
   ...

    security.declareProtected(ManageZCatalogEntries, 'catalog_object')
    def catalog_object(self, obj, uid=None, idxs=[],
                   update_metadata=1, pghandler=None):
        w = obj
        if not IIndexableObject.providedBy(obj):
            wrapper = component.queryMultiAdapter((obj, self), IIndexableObject)
            if wrapper is not None:
                w = wrapper

        ZCatalog.catalog_object(self, w, w and str("/".join(w.getPhysicalPath())), idxs,
                            update_metadata, pghandler=pghandler)

(with all GenericSetup things, also can be done similarly to Archetypes)

Subscribers for IPrincipalCreatedEvent, IPrincipalDeletedEvent, IConfigurationChangedEvent (the latter one needs event.context.class._name_ in ('UserDataConfiglet', 'PersonalPreferencesPanel', 'UserDataPanel') to be handled - unfortunately, Plone has no specific events for profile data changes). See PAS on how those work and which parameters event handlers receive.

A view /memberdata/username for the catalog to address and reindex those users. The "username" done by bobo traverse and returns an wrapped user with properties, needed for indexes and metadata.

The http://plone.org/products/collective.examples.userdata is a good guide how to actually extend the user profile.

Apart from that, an adapter is needed

class IndexableAdapter(EnhancedUserDataPanelAdapter):
    implements(IIndexableObject)
    adapts(IMemberData, IMemberdataCatalog)
    def __init__(self, context, catalog):
        self.context = context
        self.userid = context.getId()
        self.catalog = catalog
    def getPhysicalPath(self):
        return make_physical_path(self.userid)  # path to the view, which "fakes" an object
    def __getattr__(self, name):
        """ Proxing attribute accesses. """
        return getattr(self.context, name)
    # Specific indexer
    def SearchableTextIntra(self):
        ...

Here EnhancedUserDataPanelAdapter has been derived and extended from UserDataPanelAdapter.

The IMemberdataCatalog is the interface of the catalog.

It is important to put everything into metadata, even width/height of the portrait, because using .getObject() made the whole thing hundreds of times (!) slower.

The group memberships were handled separately, because there are no events, which signify changes in the groups, needed to reindex some or all memebrs.

Roman Susi
  • 4,135
  • 2
  • 32
  • 47