Commit ad8b1ee3 authored by Jean-Paul Smets's avatar Jean-Paul Smets

Added loop detection system for getAcquiredProperty API (based on request)

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1178 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 1fb47134
...@@ -133,11 +133,11 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -133,11 +133,11 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
return aq_inner(self.getPortalObject().portal_categories) return aq_inner(self.getPortalObject().portal_categories)
# Generic accessor # Generic accessor
def _getDefaultAcquiredProperty(self, key, default_value, null_value, def _getDefaultAcquiredProperty(self, key, default_value, null_value,
base_category=None, portal_type=None, copy_value=0, mask_value=0, sync_value=0, base_category=None, portal_type=None, copy_value=0, mask_value=0, sync_value=0,
accessor_id=None, depends=None, storage_id=None, alt_accessor_id=None, accessor_id=None, depends=None, storage_id=None, alt_accessor_id=None,
is_list_type=0): is_list_type=0):
""" """
This method implements programmable acquisition of values in ERP5. This method implements programmable acquisition of values in ERP5.
The principle is that some object attributes should be looked up, The principle is that some object attributes should be looked up,
...@@ -188,20 +188,33 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -188,20 +188,33 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
Other case : we want to change the phone number of a related object without Other case : we want to change the phone number of a related object without
going to edit the related object going to edit the related object
"""
"""
# Push context to prevent loop
from Globals import get_request
TRANSACTION = get_transaction()
if not hasattr(TRANSACTION, '_erp5_acquisition_stack'): TRANSACTION._erp5_acquisition_stack = {}
acquisition_key = ('_getDefaultAcquiredProperty', self.getPath(), key, base_category,
portal_type, copy_value, mask_value, sync_value,
accessor_id, depends, storage_id, alt_accessor_id, is_list_type)
if TRANSACTION._erp5_acquisition_stack.has_key(acquisition_key): return null_value
TRANSACTION._erp5_acquisition_stack[acquisition_key] = 1
#LOG("Get Acquired Property key",0,str(key)) #LOG("Get Acquired Property key",0,str(key))
if storage_id is None: storage_id=key if storage_id is None: storage_id=key
# LOG("Get Acquired Property storage_id",0,str(storage_id)) # LOG("Get Acquired Property storage_id",0,str(storage_id))
# If we hold an attribute and mask_value is set, return the attribute # If we hold an attribute and mask_value is set, return the attribute
if mask_value and hasattr(self, storage_id): if mask_value and hasattr(self, storage_id):
if getattr(self, storage_id) != None: if getattr(self, storage_id) != None:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return getattr(self, storage_id) return getattr(self, storage_id)
# Retrieve the list of related objects # Retrieve the list of related objects
#LOG("Get Acquired Property self",0,str(self)) #LOG("Get Acquired Property self",0,str(self))
#LOG("Get Acquired Property portal_type",0,str(portal_type)) #LOG("Get Acquired Property portal_type",0,str(portal_type))
#LOG("Get Acquired Property base_category",0,str(base_category)) #LOG("Get Acquired Property base_category",0,str(base_category))
#super_list = self._getValueList(base_category, portal_type=portal_type) # We only do a single jump #super_list = self._getValueList(base_category, portal_type=portal_type) # We only do a single jump
super_list = self._getAcquiredValueList(base_category, portal_type=portal_type) # We only do a single jump super_list = self._getAcquiredValueList(base_category, portal_type=portal_type) # Full acquisition
super_list = filter(lambda o: o.getPhysicalPath() != self.getPhysicalPath(), super_list) # Make sure we do not create stupid loop here super_list = filter(lambda o: o.getPhysicalPath() != self.getPhysicalPath(), super_list) # Make sure we do not create stupid loop here
#LOG("Get Acquired Property super_list",0,str(super_list)) #LOG("Get Acquired Property super_list",0,str(super_list))
#LOG("Get Acquired Property accessor_id",0,str(accessor_id)) #LOG("Get Acquired Property accessor_id",0,str(accessor_id))
...@@ -237,6 +250,8 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -237,6 +250,8 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
else: else:
result = None result = None
if result is not None: if result is not None:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return result return result
else: else:
#LOG("alt_accessor_id",0,str(alt_accessor_id)) #LOG("alt_accessor_id",0,str(alt_accessor_id))
...@@ -251,20 +266,30 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -251,20 +266,30 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
if type(result) is type([]) or type(result) is type(()): if type(result) is type([]) or type(result) is type(()):
# We must provide the first element of the alternate result # We must provide the first element of the alternate result
if len(result) > 0: if len(result) > 0:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return result[0] return result[0]
else: else:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return result return result
else: else:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
# Result is a simple type # Result is a simple type
return result return result
if copy_value: if copy_value:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return getattr(self,storage_id, default_value) return getattr(self,storage_id, default_value)
else: else:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
# Return the default value defined at the class level XXXXXXXXXXXXXXX # Return the default value defined at the class level XXXXXXXXXXXXXXX
return default_value return default_value
def _getAcquiredPropertyList(self, key, default_value, null_value, def _getAcquiredPropertyList(self, key, default_value, null_value,
base_category, portal_type=None, copy_value=0, mask_value=0, sync_value=0, append_value=0, base_category, portal_type=None, copy_value=0, mask_value=0, sync_value=0, append_value=0,
accessor_id=None, depends=None, storage_id=None, alt_accessor_id=None, accessor_id=None, depends=None, storage_id=None, alt_accessor_id=None,
is_list_type=0): is_list_type=0):
...@@ -275,10 +300,23 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -275,10 +300,23 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
portal_type portal_type
copy_value copy_value
depends depends
"""
"""
# Push context to prevent loop
from Globals import get_request
TRANSACTION = get_transaction()
if not hasattr(TRANSACTION, '_erp5_acquisition_stack'): TRANSACTION._erp5_acquisition_stack = {}
acquisition_key = ('_getAcquiredPropertyList', self.getPath(), key, base_category,
portal_type, copy_value, mask_value, sync_value,
accessor_id, depends, storage_id, alt_accessor_id, is_list_type)
if TRANSACTION._erp5_acquisition_stack.has_key(acquisition_key): return null_value
TRANSACTION._erp5_acquisition_stack[acquisition_key] = 1
if storage_id is None: storage_id=key if storage_id is None: storage_id=key
if mask_value and hasattr(self, storage_id): if mask_value and hasattr(self, storage_id):
if getattr(self, storage_id) != None: if getattr(self, storage_id) != None:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return getattr(self, storage_id) return getattr(self, storage_id)
if type(base_category) == 'a': if type(base_category) == 'a':
base_category = (base_category, ) base_category = (base_category, )
...@@ -288,7 +326,7 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -288,7 +326,7 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
psuper = [] psuper = []
for cat in base_category: for cat in base_category:
#super_list = self._getValueList(cat) # We only do a single jump - no acquisition #super_list = self._getValueList(cat) # We only do a single jump - no acquisition
super_list = self._getAcquiredValueList(cat) # We only do a single jump - no acquisition super_list = self._getAcquiredValueList(cat) # Full acquisition
for super in super_list: for super in super_list:
if super is not None: if super is not None:
# Performance should be increased # Performance should be increased
...@@ -320,12 +358,18 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -320,12 +358,18 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
if copy_value: if copy_value:
if not hasattr(self, storage_id): if not hasattr(self, storage_id):
setattr(self, value) setattr(self, value)
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return value return value
else: else:
# ????? # ?????
if copy_value: if copy_value:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return getattr(self,storage_id, default_value) return getattr(self,storage_id, default_value)
else: else:
# Pop context
del TRANSACTION._erp5_acquisition_stack[acquisition_key]
return default_value return default_value
security.declareProtected( Permissions.AccessContentsInformation, 'getProperty' ) security.declareProtected( Permissions.AccessContentsInformation, 'getProperty' )
...@@ -460,6 +504,7 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -460,6 +504,7 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
except: except:
categoryIds = [] categoryIds = []
id_changed = 0 id_changed = 0
self._v_modified_property_dict = {}
for key in kw.keys(): for key in kw.keys():
#if key in categoryIds: #if key in categoryIds:
# self._setCategoryMembership(key, kw[key]) # self._setCategoryMembership(key, kw[key])
...@@ -472,12 +517,13 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana ...@@ -472,12 +517,13 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
elif hasattr(self, accessor_name): elif hasattr(self, accessor_name):
#LOG("Calling: ",0, accessor_name) #LOG("Calling: ",0, accessor_name)
method = getattr(self, accessor_name) method = getattr(self, accessor_name)
old_value = method() old_value = method() # XXX Why not use getProperty ???
#LOG("Old value: ",0, str(old_value)) #LOG("Old value: ",0, str(old_value))
#LOG("New value: ",0, str(kw[key])) #LOG("New value: ",0, str(kw[key]))
else: else:
old_value = None old_value = None
if old_value != kw[key] or force_update: if old_value != kw[key] or force_update:
self._v_modified_property_dict[key] = old_value # We keep in a thread var the previous values - this can be useful for interaction workflow to implement lookups
self._setProperty(key, kw[key]) self._setProperty(key, kw[key])
elif self.id != kw['id']: elif self.id != kw['id']:
self.recursiveFlushActivity(invoke=1) # Do not rename until everything flushed self.recursiveFlushActivity(invoke=1) # Do not rename until everything flushed
......
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