from Products.CMFCore.CatalogTool import CatalogTool as BaseCatalogTool
from Products.CMFCore.CatalogTool import IndexableObjectWrapper
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from Products.CMFCore.permissions import ModifyPortalContent
+from Products.CMFCore.permissions import ModifyPortalContent, ManagePortal
from zope.component import queryMultiAdapter
from Products.ZCatalog.Catalog import Catalog
import transaction
from BTrees.IIBTree import weightedIntersection
import warnings
+_VOLATILE_SOLR_NAME = '_v_solrConnection'
+
class SolrTransactionHook :
''' commit solr couplé sur le commit de la ZODB '''
- def __init__(self, connection) :
- self.connection = connection
+ def __init__(self, context, con) :
+ self.context = context
+ self.con = con
def __call__(self, status) :
if status :
- self.connection.commit()
- self.connection.close()
+ self.con.commit()
+ self.con.close()
else :
- self.connection.close()
+ self.con.close()
+ try :
+ delattr(self.context, _VOLATILE_SOLR_NAME)
+ except AttributeError :
+ pass
class CatalogTool(BaseCatalogTool) :
- meta_type = 'Legivoc Catalog'
+ meta_type = 'Plinn Catalog'
security = ClassSecurityInfo()
manage_options = (BaseCatalogTool.manage_options[:5] +
({'label' : 'Solr', 'action' : 'manage_solr'},) +
BaseCatalogTool.manage_options[5:])
- manage_solr = PageTemplateFile('www/manage_solr', globals())
+ manage_solr = PageTemplateFile('www/manage_solr.pt', globals(), __name__='manage_solr')
+
def __init__(self, idxs=[]) :
self.solr_url = 'http://localhost:8983/solr'
self.delegatedIndexes = ('Title', 'Description', 'SearchableText')
+ security.declarePublic('getDelegatedIndexes')
+ def getDelegatedIndexes(self) :
+ """ read the method name """
+ return self.delegatedIndexes
+
+ security.declareProtected(ManagePortal, 'setSolrProperties')
+ def setSolrProperties(self, url, indexes, REQUEST=None) :
+ """ set Solr server url and delegated indexes """
+ self.solr_url = url
+ self.delegatedIndexes = tuple([i.strip() for i in indexes if i.strip()])
+ if REQUEST :
+ REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_solr?manage_tabs_message=Saved changes.')
+
+ def _getSolrConnection(self) :
+ if not hasattr(self, _VOLATILE_SOLR_NAME) :
+ con = SolrConnection(self.solr_url)
+ setattr(self, _VOLATILE_SOLR_NAME, con)
+ txn = transaction.get()
+ txn.addAfterCommitHook(SolrTransactionHook(self, con))
+ return getattr(self, _VOLATILE_SOLR_NAME)
+
security.declarePrivate('solrAdd')
- def solrAdd(self, object, idxs=[], uid=None) :
- if IIndexableObject.providedBy(object):
- w = object
- else:
- w = queryMultiAdapter( (object, self), IIndexableObject )
- if w is None:
- # BBB
- w = IndexableObjectWrapper(object, self)
-
- uid = uid if uid else self.__url(object)
- idxs = idxs if idxs !=[] else self.delegatedIndexes
+ def solrAdd(self, w, uid, idxs) :
+ idxs = idxs if idxs else self.delegatedIndexes
+ # Filter out delegated indexes
+ idxs = [i for i in idxs if i in self.delegatedIndexes]
data = {'id' : uid}
for name in idxs :
attr = getattr(w, name, '')
data[name] = attr() if callable(attr) else attr
- c = SolrConnection(self.solr_url)
+ c = self._getSolrConnection()
c.add(**data)
- txn = transaction.get()
- txn.addAfterCommitHook(SolrTransactionHook(c))
-
# PortalCatalog api overloads
- security.declareProtected(ModifyPortalContent, 'indexObject')
- def indexObject(self, object) :
- """ Add to catalog and send to Solr """
- super(CatalogTool, self).indexObject(object)
- self.solrAdd(object)
-
- security.declarePrivate('reindexObject')
- def reindexObject(self, object, idxs=[], update_metadata=1, uid=None):
- super(CatalogTool, self).reindexObject(object,
- idxs=idxs,
- update_metadata=update_metadata,
- uid=uid)
- if idxs != []:
+ def catalog_object(self, obj, uid=None, idxs=None, update_metadata=1,
+ pghandler=None):
+ # Wraps the object with workflow and accessibility
+ # information just before cataloging.
+ if IIndexableObject.providedBy(obj):
+ w = obj
+ else:
+ w = queryMultiAdapter( (obj, self), IIndexableObject )
+ if w is None:
+ # BBB
+ w = IndexableObjectWrapper(obj, self)
+
+ idxs_ = idxs
+ if idxs:
# Filter out invalid indexes.
valid_indexes = self._catalog.indexes.keys()
- idxs = [i for i in idxs if i in valid_indexes and i in self.delegatedIndexes]
- else :
- idxs = self.delegatedIndexes
+ idxs_ = [i for i in idxs if i in valid_indexes]
+
+ super(CatalogTool, self).catalog_object(w, uid, idxs_, update_metadata, pghandler)
+ self.solrAdd(w, uid, idxs)
+
+ security.declarePrivate('reindexObject')
+ def reindexObject(self, object, idxs=[], update_metadata=1, uid=None):
+ """Update catalog after object data has changed.
+
+ The optional idxs argument is a list of specific indexes
+ to update (all of them by default).
- if idxs :
- self.solrAdd(object, idxs=idxs, uid=uid)
+ The update_metadata flag controls whether the object's
+ metadata record is updated as well.
+
+ If a non-None uid is passed, it will be used as the catalog uid
+ for the object instead of its physical path.
+ """
+ if uid is None:
+ uid = self.__url(object)
+
+ self.catalog_object(object, uid, idxs, update_metadata)
security.declarePrivate('unindexObject')
def unindexObject(self, object):
"""Remove from catalog.
"""
super(CatalogTool, self).unindexObject(object)
- c = SolrConnection(self.solr_url)
+ c = self._getSolrConnection()
url = self.__url(object)
c.delete(id=url)
- txn = transaction.get()
- txn.addAfterCommitHook(SolrTransactionHook(c))
InitializeClass(CatalogTool)
Catalog.__init__(self, brains=brains)
self.zcat = zcat
- def getDelegatedIndexes(self) :
- return ('Title', 'Description', 'SearchableText') # <= TODO virer cette ligne
- return self.zcat.delegatedIndexes
-
def delegateSearch(self, query, plan) :
'''
retours faux :
- None signifie : pas de délégation, il faut continue à interroger les autres index
+ None signifie : pas de délégation, il faut continuer à interroger les autres index.
IISet() vide : pas de résultat lors de la délégation, on peut arrêter la recherche.
'''
- indexes = set(plan).intersection(set(self.getDelegatedIndexes()))
+ indexes = set(query.keys()).intersection(set(self.zcat.delegatedIndexes))
+ if not indexes :
+ return None
delegatedQuery = {}
for i in indexes :
delegatedQuery[i] = query.pop(i)
- plan.remove(i)
- if not delegatedQuery :
- return None
- c = SolrConnection('http://localhost:8983/solr')
+ try : plan.remove(i)
+ except ValueError : pass
+ c = SolrConnection(self.zcat.solr_url)
q =' AND '.join(['%s:"%s"' % item for item in delegatedQuery.items()])
- resp = c.query(q, fields='id')
+ resp = c.query(q, fields='id', rows=len(self))
+ c.close()
return IISet(filter(None, [self.uids.get(r['id']) for r in resp.results]))
def search(self, query, sort_index=None, reverse=0, limit=None, merge=1):