Commit 3caddcdf authored by Julien Muchembled's avatar Julien Muchembled

Allow portal types to customize dynamically initialization of property holders

* Replace direct access to some ERP5TypeInformation attributes by use of
  accessors:
  - base_category_list -> getTypeBaseCategoryList
  - property_sheet_list -> getTypePropertySheetList
* Split Base.initializePortalTypeDynamicProperties to delegate some work to
  portal types (new 'updatePropertySheetDefinitionDict' method).

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@30159 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 9fd4bc75
......@@ -98,8 +98,9 @@ class TestCMFCategory(ERP5TypeTestCase):
organisation_ti = self.getTypesTool().getTypeInfo('Organisation')
organisation_ti.filter_content_types = 0
# we also enable 'destination' category on organisations
self._organisation_categories = cat = organisation_ti.base_category_list
organisation_ti.base_category_list = tuple(list(cat) + ['destination'])
self._organisation_categories = organisation_ti.getTypeBaseCategoryList()
organisation_ti._setTypeBaseCategoryList(self._organisation_categories
+ ['destination'])
# Make persons.
person_module = self.getPersonModule()
......
......@@ -89,7 +89,7 @@ class TestERP5Category(ERP5TypeTestCase):
# associate base categories on Organisation portal type
portal_type = self.getTypeTool()[self.portal_type]
portal_type.base_category_list = [self.base_cat, self.base_cat2]
portal_type._setTypeBaseCategoryList([self.base_cat, self.base_cat2])
# Reset aq dynamic
_aq_reset()
......@@ -322,8 +322,8 @@ class TestERP5Category(ERP5TypeTestCase):
# associate the base category with our portal types
ttool = self.getTypesTool()
ttool['Organisation'].base_category_list = ['test_aq_category']
ttool['Telephone'].base_category_list = ['test_aq_category']
ttool['Organisation']._setTypeBaseCategoryList(['test_aq_category'])
ttool['Telephone']._setTypeBaseCategoryList(['test_aq_category'])
doc = self.organisation
subdoc = doc['1']
......
......@@ -145,9 +145,9 @@ class TestERP5Core(ERP5TypeTestCase, ZopeTestCase.Functional):
self.portal.unittest_module.getShortTitleTranslationDomain())
type_information = self.portal.portal_types[module_portal_type]
self.assertTrue('business_application' in type_information.base_category_list)
self.assertTrue('business_application'
in type_information.getTypeBaseCategoryList())
def test_02_FavouritesMenu(self, quiet=quiet, run=run_all_test):
"""
Test that Manage members is not an entry in the My Favourites menu.
......
......@@ -75,7 +75,7 @@ class TestInteractionWorkflow(ERP5TypeTestCase):
Organisation = Products.ERP5Type.Document.Organisation.Organisation
Organisation.doSomethingStupid = doSomethingStupid
portal_type = self.getTypeTool()['Organisation']
portal_type.base_category_list = ['size']
portal_type._setTypeBaseCategoryList(['size'])
organisation_module = self.getOrganisationModule()
self.organisation = organisation_module.newContent(
portal_type = self.portal_type)
......
......@@ -2161,16 +2161,7 @@ class TestInventoryDocument(InventoryAPITestCase):
does not allow such things
"""
portal = self.getPortal()
portal_type_name = 'Inventory'
property_sheet_name = 'InventoryConstraint'
# We set the property sheet on the portal type
ti = self.getTypesTool().getTypeInfo(portal_type_name)
ti.property_sheet_list = list(ti.property_sheet_list) +\
[property_sheet_name]
# reset aq_dynamic cache
_aq_reset()
self._addPropertySheet('Inventory', 'InventoryConstraint')
try:
inventory_module = portal.getDefaultModule(portal_type='Inventory')
inventory = inventory_module.newContent(portal_type='Inventory')
......@@ -2222,17 +2213,16 @@ class TestInventoryDocument(InventoryAPITestCase):
self.assertTrue(len([x for x in workflow_error_message \
if x.find('There is already an inventory')]))
finally:
# remove all property sheet we added to type informations
# remove all property sheets we added to type informations
ttool = self.getTypesTool()
ti = ttool.getTypeInfo(portal_type_name)
ps_list = ti.property_sheet_list
psheet_list = [property_sheet_name]
for psheet in psheet_list:
if psheet in ps_list:
ps_list.remove(psheet)
ti.property_sheet_list = ps_list
for ti_name, psheet_list in self._added_property_sheets.iteritems():
ti = ttool.getTypeInfo(ti_name)
property_sheet_set = set(ti.getTypePropertySheetList())
property_sheet_set.difference_update(psheet_list)
ti._setTypePropertySheetList(list(property_sheet_set))
transaction.commit()
_aq_reset()
def test_15_InventoryAfterModificationInFuture(self):
"""
Test inventory after adding a new movement in future
......
......@@ -197,19 +197,18 @@ class ResourceVariationTestCase(ERP5TypeTestCase):
#adding to base categories of resources
#for use setRequiredSizeList and setOptionColourList methods
self.portal.portal_types['Product'].base_category_list = [
self.portal.portal_types['Product']._setTypeBaseCategoryList([
'required_size',
'option_colour',
'individual_aspect']
self.portal.portal_types['Service'].base_category_list = [
'individual_aspect'])
self.portal.portal_types['Service']._setTypeBaseCategoryList([
'required_size',
'option_colour',
'individual_aspect']
self.portal.portal_types['Component'].base_category_list = [
'individual_aspect'])
self.portal.portal_types['Component']._setTypeBaseCategoryList([
'required_size',
'option_colour',
'individual_aspect']
'individual_aspect'])
transaction.commit()
self.tic()
......
......@@ -150,12 +150,7 @@ class TestWorklist(ERP5TypeTestCase):
return int(action_name[left_parenthesis_offset + 1:-1])
def associatePropertySheet(self):
from Products.ERP5Type.Base import _aq_reset
ti = self.getTypesTool().getTypeInfo(self.checked_portal_type)
ti.property_sheet_list = list(ti.property_sheet_list) + \
['SortIndex']
# reset aq_dynamic cache
_aq_reset()
self._addPropertySheet(self.checked_portal_type, 'SortIndex')
def addWorkflowCataloguedVariable(self, workflow_id, variable_id):
variables = self.getWorkflowTool()[workflow_id].variables
......
......@@ -68,37 +68,28 @@ def createPreferenceToolAccessorList(portal) :
property sheets by looking at all registered property sheets
and considering those which name ends with 'Preference'
"""
attr_list = []
typestool = getToolByName(portal, 'portal_types')
pref_portal_type = typestool.getTypeInfo('Preference')
property_list = []
# 'Dynamic' property sheets added through ZMI
zmi_property_sheet_list = []
# 'Dynamic' property sheets added by portal_type
pref_portal_type = portal.portal_types.getTypeInfo('Preference')
if pref_portal_type is None:
LOG('ERP5Form.PreferenceTool', PROBLEM,
'Preference type information is not installed.')
'Preference type information is not installed.')
else:
for property_sheet in pref_portal_type.property_sheet_list :
try:
zmi_property_sheet_list.append(
getattr(__import__(property_sheet), property_sheet))
except ImportError, e :
LOG('ERP5Form.PreferenceTool', PROBLEM,
'unable to import Property Sheet %s' % property_sheet, e)
pref_portal_type.updatePropertySheetDefinitionDict(
{'_properties': property_list})
# 'Static' property sheets defined on the class
# The Preference class should be imported from the common location
# in ERP5Type since it could be overloaded in another product
from Products.ERP5Type.Document.Preference import Preference
class_property_sheet_list = Preference.property_sheets
# We can now merge
for property_sheet in ( tuple(zmi_property_sheet_list) +
class_property_sheet_list ) :
# then generate common method names
for prop in property_sheet._properties :
if not prop.get('preference', 0) :
# only properties marked as preference are used
continue
for property_sheet in Preference.property_sheets:
property_list += property_sheet._properties
# Generate common method names
for prop in property_list:
if prop.get('preference'):
# only properties marked as preference are used
attribute = prop['id']
attr_list = [ 'get%s' % convertToUpperCase(attribute)]
if prop['type'] in list_types :
......
......@@ -549,41 +549,29 @@ def initializePortalTypeDynamicProperties(self, klass, ptype, aq_key, portal):
initializePortalTypeDynamicProperties(parent_object, parent_klass,
parent_type,
parent_object._aq_key(), portal)
# Initiatise portal_type properties (XXX)
ptype_object = getattr(aq_base(portal.portal_types), ptype, None)
prop_list = list(getattr(klass, '_properties', []))
cat_list = list(getattr(klass, '_categories', []))
constraint_list = list(getattr(klass, '_constraints', []))
ps_definition_dict = {'_properties': prop_list,
'_categories': cat_list,
'_constraints': constraint_list}
# Initialize portal_type properties (XXX)
# Always do it before processing klass.property_sheets (for compatibility).
# Because of the order we generate accessors, it is still possible
# to overload data access for some accessors.
ptype_object = portal.portal_types._getOb(ptype, None)
if ptype_object is not None:
# Make sure this is an ERP5Type object
ps_list = [getattr(PropertySheet, p, None) for p in
ptype_object.property_sheet_list]
ps_list = [p for p in ps_list if p is not None]
# Always append the klass.property_sheets to this list (for compatibility)
# Because of the order we generate accessors, it is still possible
# to overload data access for some accessors
ps_list = tuple(ps_list) + getClassPropertyList(klass)
#LOG('ps_list',0, str(ps_list))
else:
ps_list = getClassPropertyList(klass)
for base in ps_list:
property_sheet_definition_dict = {
'_properties': prop_list,
'_categories': cat_list,
'_constraints': constraint_list
}
for ps_property_name, current_list in \
property_sheet_definition_dict.items():
if hasattr(base, ps_property_name):
ps_property = getattr(base, ps_property_name)
if isinstance(ps_property, (tuple, list)):
current_list += ps_property
else :
raise ValueError, "%s is not a list for %s" % (ps_property_name,
base)
ptype_object.updatePropertySheetDefinitionDict(ps_definition_dict)
for base in getClassPropertyList(klass):
for list_name, current_list in ps_definition_dict.items():
try:
current_list += getattr(base, list_name, ())
except TypeError:
raise ValueError("%s is not a list for %s" % (list_name, base))
if ptype_object is not None:
cat_list += ptype_object.base_category_list
prop_holder._portal_type = ptype
prop_holder._properties = prop_list
prop_holder._categories = cat_list
......
......@@ -420,6 +420,33 @@ class ERP5TypeInformation(XMLObject,
return ob
security.declarePrivate('updatePropertySheetDefinitionDict')
def updatePropertySheetDefinitionDict(self, definition_dict):
for property_sheet_name in self.getTypePropertySheetList():
base = getattr(PropertySheet, property_sheet_name, None)
if base is not None:
for list_name, property_list in definition_dict.items():
try:
property_list += getattr(base, list_name, ())
except TypeError:
raise ValueError("%s is not a list for %s" % (list_name, base))
if '_categories' in definition_dict:
definition_dict['_categories'] += self.getTypeBaseCategoryList()
# The following 2 methods are needed before there are generated.
security.declareProtected(Permissions.AccessContentsInformation,
'getTypePropertySheetList')
def getTypePropertySheetList(self):
"""Getter for 'type_property_sheet' property"""
return list(self.property_sheet_list)
security.declareProtected(Permissions.AccessContentsInformation,
'getTypeBaseCategoryList')
def getTypeBaseCategoryList(self):
"""Getter for 'type_base_category' property"""
return list(self.base_category_list)
security.declareProtected(Permissions.AccessContentsInformation,
'getInstanceBaseCategoryList')
def getInstanceBaseCategoryList(self):
......@@ -534,8 +561,8 @@ class ERP5TypeInformation(XMLObject,
self.getTypeFactoryMethodId(),
self.getTypeAddPermission(),
self.getTypeInitScriptId()]
search_source_list += self.getTypePropertySheetList(())
search_source_list += self.getTypeBaseCategoryList(())
search_source_list += self.getTypePropertySheetList()
search_source_list += self.getTypeBaseCategoryList()
return ' '.join(filter(None, search_source_list))
security.declarePrivate('getDefaultViewFor')
......
......@@ -57,40 +57,24 @@ class TranslationProviderBase(object):
Create the initial list of association between property and domain name
"""
property_domain_dict = {}
ptype_object = self
# get the klass of the object based on the constructor document
m = Products.ERP5Type._m
ptype_name = ''.join(ptype_object.id.split(' '))
constructor = self.factory # This is safer than: 'add%s' %(ptype_name)
klass = None
for method, doc in m.items():
if method == constructor:
klass = doc.klass
break
# get the property sheet list for the portal type
# from the list of property sheet defined on the portal type
ps_list = map(lambda p: getattr(PropertySheet, p, None),
ptype_object.property_sheet_list)
ps_list = filter(lambda p: p is not None, ps_list)
# from the property sheets defined on the class
if klass is not None:
from Products.ERP5Type.Base import getClassPropertyList
ps_list = tuple(ps_list) + getClassPropertyList(klass)
# get all properties from the property sheet list
current_list = []
for base in ps_list:
if hasattr(base, '_properties'):
# XXX must check that property is translatable
ps_property = getattr(base, '_properties')
if type(ps_property) in (type(()), type([])):
current_list += ps_property
ps_list = [getattr(PropertySheet, p, None)
for p in self.getTypePropertySheetList()]
m = Products.ERP5Type._m
if m.has_key(self.factory):
klass = m[self.factory].klass
if klass is not None:
from Products.ERP5Type.Base import getClassPropertyList
ps_list += getClassPropertyList(klass)
# create TranslationInformation object for each property
for prop in current_list:
if prop.get('translatable', 0):
for base in ps_list:
for prop in getattr(base, '_properties', ()):
prop_id = prop['id']
if not property_domain_dict.has_key(prop_id):
domain_name = prop.get('translation_domain', None)
property_domain_dict[prop_id] = TranslationInformation(prop_id, domain_name)
if prop.get('translatable') and prop_id not in property_domain_dict:
domain_name = prop.get('translation_domain')
property_domain_dict[prop_id] = TranslationInformation(prop_id,
domain_name)
original_property_domain_dict = getattr(aq_base(self),
'_property_domain_dict', _MARKER)
......
......@@ -422,6 +422,9 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
global current_app
current_app = self.app
self._updateConnectionStrings()
# keep a mapping type info name -> property sheet list, to remove them in
# tear down.
self._added_property_sheets = {}
def afterSetUp(self):
'''Called after setUp() has completed. This is
......@@ -563,16 +566,15 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
class_tool.editPropertySheet(property_sheet_name, property_sheet_code)
transaction.commit()
class_tool.importPropertySheet(property_sheet_name)
# We set the property sheet on the portal type
ti = self.getTypesTool().getTypeInfo(portal_type_name)
if property_sheet_name not in ti.property_sheet_list:
ti.property_sheet_list = list(ti.property_sheet_list) +\
[property_sheet_name]
property_sheet_set = set(ti.getTypePropertySheetList())
property_sheet_set.add(property_sheet_name)
ti._setTypePropertySheetList(list(property_sheet_set))
# remember that we added a property sheet for tear down
if getattr(self, '_added_property_sheets', None) is not None:
self._added_property_sheets.setdefault(
self._added_property_sheets.setdefault(
portal_type_name, []).append(property_sheet_name)
# reset aq_dynamic cache
_aq_reset()
......
......@@ -63,9 +63,6 @@ class PropertySheetTestCase(ERP5TypeTestCase):
"""Set up the fixture. """
ERP5TypeTestCase.setUp(self)
installRealClassTool(self.getPortal())
# keep a mapping type info name -> property sheet list, to remove them in
# tear down.
self._added_property_sheets = {}
def tearDown(self):
"""Clean up """
......@@ -75,14 +72,14 @@ class PropertySheetTestCase(ERP5TypeTestCase):
# remove all property sheet we added to type informations
for ti_name, psheet_list in self._added_property_sheets.items():
ti = ttool.getTypeInfo(ti_name)
ps_list = ti.property_sheet_list
property_sheet_set = set(ti.getTypePropertySheetList())
for psheet in psheet_list:
if psheet in ps_list:
ps_list.remove(psheet)
if psheet in property_sheet_set:
property_sheet_set.remove(psheet)
# physically remove property sheet, otherwise invalid property sheet
# could break next tests.
removeLocalPropertySheet(psheet)
ti.property_sheet_list = ps_list
ti._setTypePropertySheetList(list(property_sheet_set))
transaction.commit()
_aq_reset()
ERP5TypeTestCase.tearDown(self)
......@@ -1232,10 +1229,9 @@ class TestPropertySheet:
self._addProperty('Person', self.DEFAULT_ORGANISATION_TITLE_ACQUIRED_PROP)
# add destination base category to Person TI
person_ti = self.getTypesTool().getTypeInfo('Person')
if 'destination' not in person_ti.base_category_list:
person_ti.base_category_list = tuple(list(
self.getTypesTool().getTypeInfo('Person').base_category_list) +
['destination', ])
base_category_list = person_ti.getTypeBaseCategoryList()
if 'destination' not in base_category_list:
person_ti._setTypeBaseCategoryList(base_category_list + ['destination'])
_aq_reset()
person = self.getPersonModule().newContent(id='1', portal_type='Person')
......@@ -1265,11 +1261,11 @@ class TestPropertySheet:
self._addProperty('Person', self.DEFAULT_ORGANISATION_TITLE_ACQUIRED_PROP)
# add destination base category to Person TI
person_ti = self.getTypesTool().getTypeInfo('Person')
if 'destination' not in person_ti.base_category_list:
person_ti.base_category_list = tuple(list(
self.getTypesTool().getTypeInfo('Person').base_category_list) +
['destination', ])
base_category_list = person_ti.getTypeBaseCategoryList()
if 'destination' not in base_category_list:
person_ti._setTypeBaseCategoryList(base_category_list + ['destination'])
_aq_reset()
person = self.getPersonModule().newContent(id='1', portal_type='Person')
another_person = self.getPersonModule().newContent(
id='default_organisation',
......@@ -2179,7 +2175,7 @@ class TestPropertySheet:
ti = self.getTypesTool()['Person']
self.assertFalse(hasattr(doc, 'getDestination'))
ti.edit(type_base_category_list=
ti.getTypeBaseCategoryList(()) + ['destination'])
ti.getTypeBaseCategoryList() + ['destination'])
self.assertTrue(hasattr(doc, 'getDestination'))
def test_aq_reset_on_workflow_chain_change(self):
......
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