Commit 6bf9e694 authored by Julien Muchembled's avatar Julien Muchembled

Merge support for ZODB indexing of category related documents

parents a7780bc6 7865c58d
This diff is collapsed.
...@@ -544,7 +544,8 @@ class BaseTemplateItem(Implicit, Persistent): ...@@ -544,7 +544,8 @@ class BaseTemplateItem(Implicit, Persistent):
klass = obj.__class__ klass = obj.__class__
classname = klass.__name__ classname = klass.__name__
attr_set = set(('_dav_writelocks', '_filepath', '_owner', 'last_id', 'uid', attr_set = set(('_dav_writelocks', '_filepath', '_owner', '_related_index',
'last_id', 'uid',
'__ac_local_roles__', '__ac_local_roles_group_id_dict__')) '__ac_local_roles__', '__ac_local_roles_group_id_dict__'))
if export: if export:
if not keep_workflow_history: if not keep_workflow_history:
......
...@@ -40,6 +40,7 @@ from Products.ERP5Type.Core.Folder import OFS_HANDLER ...@@ -40,6 +40,7 @@ from Products.ERP5Type.Core.Folder import OFS_HANDLER
from Products.ERP5Type.CopySupport import CopyContainer from Products.ERP5Type.CopySupport import CopyContainer
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Cache import caching_instance_method from Products.ERP5Type.Cache import caching_instance_method
from Products.ERP5Type.dynamic import portal_type_class
from zLOG import LOG from zLOG import LOG
...@@ -84,54 +85,10 @@ class CategoryTool(CopyContainer, CMFCategoryTool, BaseTool): ...@@ -84,54 +85,10 @@ class CategoryTool(CopyContainer, CMFCategoryTool, BaseTool):
def hasContent(self,id): def hasContent(self,id):
return id in self.objectIds() return id in self.objectIds()
security.declareProtected(Permissions.AccessContentsInformation, 'getCategoryParentUidList') @caching_instance_method(
def getCategoryParentUidList(self, relative_url, base_category = None, strict=0): id='portal_categories.getBaseCategoryDict',
""" cache_factory='erp5_content_long',
Returns the uids of all categories provided in categorie. This cache_id_generator=lambda *a: portal_type_class.last_sync)
method can support relative_url such as site/group/a/b/c which
base category is site yet use categories defined in group.
It is also able to use acquisition to create complex categories
such as site/group/a/b/c/b1/c1 where b and b1 are both children
categories of a.
relative_url -- a single relative url of a list of
relative urls
strict -- if set to 1, only return uids of parents, not
relative_url
"""
uid_dict = {}
if type(relative_url) is type('a'): relative_url = (relative_url,)
for path in relative_url:
try:
o = self.getCategoryValue(path, base_category=base_category)
if o is not None:
if base_category is None:
my_base_category = self.getBaseCategoryId(path)
else:
my_base_category = base_category
bo = getattr(self, my_base_category, None)
if bo is not None:
bo_uid = bo.getUid()
uid_dict[(o.getUid(), bo_uid, 1)] = 1 # Strict membership
if o.meta_type == 'ERP5 Category' or o.meta_type == 'ERP5 Base Category' or \
o.meta_type == 'CMF Category' or o.meta_type == 'CMF Base Category':
# This goes up in the category tree
# XXX we should also go up in some other cases....
# ie. when some documents act as categories
if not strict:
while o.meta_type == 'ERP5 Category' or o.meta_type == 'CMF Category':
o = o.aq_parent # We want acquisition here without aq_inner
uid_dict[(o.getUid(), bo_uid, 0)] = 1 # Non strict
except (TypeError, KeyError):
LOG('WARNING: CategoriesTool',0, 'Unable to find uid for %s' % path)
return uid_dict.keys()
security.declareProtected(Permissions.AccessContentsInformation, 'getUids')
getUids = getCategoryParentUidList
@caching_instance_method(id='portal_categories.getBaseCategoryDict', cache_factory='erp5_content_long', cache_id_generator=lambda m, *a, **k:m)
def getBaseCategoryDict(self): def getBaseCategoryDict(self):
""" """
Cached method to which resturns a dict with category names as keys, and None as values. Cached method to which resturns a dict with category names as keys, and None as values.
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return not (value and (\n
request.other[\'field_my_acquisition_object_id_list\'] or\n
request.other[\'field_my_acquisition_base_category_list\']))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>value, request</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BaseCategory_validateRelatedLocallyIndexed</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
<key> <string>right</string> </key> <key> <string>right</string> </key>
<value> <value>
<list> <list>
<string>my_related_locally_indexed</string>
<string>my_acquisition_copy_value</string> <string>my_acquisition_copy_value</string>
<string>my_acquisition_mask_value</string> <string>my_acquisition_mask_value</string>
<string>my_acquisition_append_value</string> <string>my_acquisition_append_value</string>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>external_validator</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>delegated_message_list</string> </key>
<value>
<list>
<string>external_validator_failed</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_related_locally_indexed</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>Local index is incompatible with category acquision.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_checkbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Index Related Documents Locally</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>BaseCategory_validateRelatedLocallyIndexed</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -58,15 +58,11 @@ order_by_expression</string> </value> ...@@ -58,15 +58,11 @@ order_by_expression</string> </value>
<key> <string>src</string> </key> <key> <string>src</string> </key>
<value> <string encoding="cdata"><![CDATA[ <value> <string encoding="cdata"><![CDATA[
SELECT DISTINCT catalog.uid, catalog.path, portal_type\n SELECT DISTINCT catalog.uid, path, relative_url, portal_type\n
FROM catalog, category\n FROM catalog, category\n
WHERE catalog.uid = category.uid\n WHERE catalog.uid = category.uid\n
<dtml-if portal_type>\n <dtml-if portal_type>\n
AND\n AND <dtml-sqltest portal_type type="string" multiple>\n
(<dtml-in portal_type>\n
<dtml-unless sequence-start> OR </dtml-unless>\n
catalog.portal_type=\'<dtml-var sequence-item>\'\n
</dtml-in>)\n
</dtml-if>\n </dtml-if>\n
AND (<dtml-var "portal_categories.buildSQLSelector(category_list)">)\n AND (<dtml-var "portal_categories.buildSQLSelector(category_list)">)\n
<dtml-if strict_membership>\n <dtml-if strict_membership>\n
......
41060 41061
\ No newline at end of file \ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/boolean</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Determines if related values should be indexed on target documents (i.e. in ZODB) in addition to catalog.\n
This is incompatible with category acquisition.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>related_locally_indexed_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: 0</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
56 57
\ No newline at end of file \ No newline at end of file
...@@ -862,20 +862,19 @@ class TestResource(ERP5TypeTestCase): ...@@ -862,20 +862,19 @@ class TestResource(ERP5TypeTestCase):
self.tic() self.tic()
# Test the cases # Test the cases
for product, variation, node, base_price in test_case_list: for product, variation, node, base_price in test_case_list:
categories = []
if node is not None: if node is not None:
self.logMessage("Check product %s with destination section %s" % \ self.logMessage("Check product %s with destination section %s" % \
(product.getTitle(), node.getTitle()), (product.getTitle(), node.getTitle()),
tab=1) tab=1)
self.assertEquals(base_price, categories.append('destination_section/' + node.getRelativeUrl())
product.getPrice(
categories=['destination_section/%s' % node.getRelativeUrl(),
variation]))
else: else:
self.logMessage("Check product %s without destination section" % \ self.logMessage("Check product %s without destination section" % \
product.getTitle(), product.getTitle(),
tab=1) tab=1)
self.assertEquals(base_price, if variation:
product.getPrice(categories=[variation])) categories.append(variation)
self.assertEqual(base_price, product.getPrice(categories=categories))
# The following test tests Movement.getPrice, which is based on the movement # The following test tests Movement.getPrice, which is based on the movement
......
...@@ -48,8 +48,7 @@ class SetSetter(BaseSetter): ...@@ -48,8 +48,7 @@ class SetSetter(BaseSetter):
def __call__(self, instance, *args, **kw): def __call__(self, instance, *args, **kw):
if self._warning: if self._warning:
LOG("ERP5Type Deprecated Setter Id:",0, self._id) LOG("ERP5Type Deprecated Setter Id:",0, self._id)
value = set(args[0]) instance._setValue(self._key, set(args[0]),
instance._setValue(self._key, value,
spec=kw.get('spec',()), spec=kw.get('spec',()),
filter=kw.get('filter', None), filter=kw.get('filter', None),
portal_type=kw.get('portal_type',()), portal_type=kw.get('portal_type',()),
...@@ -451,7 +450,7 @@ class UidSetSetter(BaseSetter): ...@@ -451,7 +450,7 @@ class UidSetSetter(BaseSetter):
def __call__(self, instance, *args, **kw): def __call__(self, instance, *args, **kw):
if self._warning: if self._warning:
LOG("ERP5Type Deprecated Getter Id:",0, self._id) LOG("ERP5Type Deprecated Getter Id:",0, self._id)
instance._setValueUidList(self._key, args[0], instance._setValueUidList(self._key, set(args[0]),
spec=kw.get('spec',()), spec=kw.get('spec',()),
filter=kw.get('filter', None), filter=kw.get('filter', None),
portal_type=kw.get('portal_type',()), portal_type=kw.get('portal_type',()),
......
...@@ -2013,11 +2013,8 @@ class Base( CopyContainer, ...@@ -2013,11 +2013,8 @@ class Base( CopyContainer,
checked_permission=None): checked_permission=None):
# We must do an ordered list so we can not use the previous method # We must do an ordered list so we can not use the previous method
# self._setValue(id, self.portal_catalog.getObjectList(uids), spec=spec) # self._setValue(id, self.portal_catalog.getObjectList(uids), spec=spec)
references = [] references = map(self.getPortalObject().portal_catalog.getObject,
if type(uids) not in (type(()), type([])): (uids,) if isinstance(uids, (int, long)) else uids)
uids = [uids]
for uid in uids:
references.append(self.portal_catalog.getObject(uid))
self._setValue(id, references, spec=spec, filter=filter, portal_type=portal_type, self._setValue(id, references, spec=spec, filter=filter, portal_type=portal_type,
keep_default=keep_default, checked_permission=checked_permission) keep_default=keep_default, checked_permission=checked_permission)
...@@ -2178,9 +2175,6 @@ class Base( CopyContainer, ...@@ -2178,9 +2175,6 @@ class Base( CopyContainer,
""" """
return self._getCategoryTool().getAcquiredCategoryList(self) return self._getCategoryTool().getAcquiredCategoryList(self)
def _getAcquiredCategoryList(self):
return self._getCategoryTool()._getAcquiredCategoryList(self)
security.declareProtected( Permissions.ModifyPortalContent, 'setCategoryList' ) security.declareProtected( Permissions.ModifyPortalContent, 'setCategoryList' )
def setCategoryList(self, path_list): def setCategoryList(self, path_list):
self.portal_categories.setCategoryList(self, path_list) self.portal_categories.setCategoryList(self, path_list)
......
...@@ -722,27 +722,21 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor): ...@@ -722,27 +722,21 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self.assertEquals(person.getDefaultRegion(), 'alpha') self.assertEquals(person.getDefaultRegion(), 'alpha')
person.setRegionUid(alpha.getUid()) person.setRegionUid(alpha.getUid())
self.assertEquals(person.getRegion(), 'alpha') self.assertEquals(person.getRegion(), 'alpha')
person.setRegionUidList([alpha.getUid(), alpha.getUid()]) person.setRegionUidList([beta.getUid(), beta.getUid()])
self.assertEquals(person.getRegionList(), ['alpha', 'alpha']) self.assertEquals(person.getRegionList(), ['beta', 'beta'])
person.setRegionUidSet([alpha.getUid(), alpha.getUid()]) person.setRegionUidSet([alpha.getUid(), alpha.getUid()])
self.assertEquals(person.getRegionSet(), ['alpha']) self.assertEquals(person.getRegionList(), ['alpha'])
person.setRegionUidList([alpha.getUid(), beta.getUid(), alpha.getUid()]) person.setRegionUidList([alpha.getUid(), beta.getUid(), alpha.getUid()])
self.assertEquals(person.getRegionList(), ['alpha', 'beta', 'alpha']) self.assertEquals(person.getRegionList(), ['alpha', 'beta', 'alpha'])
person.setRegionUidSet([alpha.getUid(), beta.getUid(), alpha.getUid()]) person.setRegionUidSet([alpha.getUid(), beta.getUid(), alpha.getUid()])
result = person.getRegionSet() self.assertEquals(sorted(person.getRegionSet()), ['alpha', 'beta'])
result.sort()
self.assertEquals(result, ['alpha', 'beta'])
person.setDefaultRegionUid(beta.getUid()) person.setDefaultRegionUid(beta.getUid())
self.assertEquals(person.getDefaultRegion(), 'beta') self.assertEquals(person.getDefaultRegion(), 'beta')
result = person.getRegionSet() self.assertEquals(sorted(person.getRegionSet()), ['alpha', 'beta'])
result.sort()
self.assertEquals(result, ['alpha', 'beta'])
self.assertEquals(person.getRegionList(), ['beta', 'alpha']) self.assertEquals(person.getRegionList(), ['beta', 'alpha'])
person.setDefaultRegionUid(alpha.getUid()) person.setDefaultRegionUid(alpha.getUid())
self.assertEquals(person.getDefaultRegion(), 'alpha') self.assertEquals(person.getDefaultRegion(), 'alpha')
result = person.getRegionSet() self.assertEquals(sorted(person.getRegionSet()), ['alpha', 'beta'])
result.sort()
self.assertEquals(result, ['alpha', 'beta'])
self.assertEquals(person.getRegionList(), ['alpha', 'beta']) self.assertEquals(person.getRegionList(), ['alpha', 'beta'])
# Test accessor on documents rather than on categories # Test accessor on documents rather than on categories
person.setDefaultRegionUid(person.getUid()) person.setDefaultRegionUid(person.getUid())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment