Commit a5fda48a authored by Ayush Tiwari's avatar Ayush Tiwari Committed by Ayush Tiwari

erp5_catalog: Dynamic migration

And, Patch changeObjectClass extension to remove useless attributes

Copying __dict__ from one object to another brings us to situation where
we don have many objects which we don't need at all, for example, migrating
objects with subclasses who were initially OFS objects and later an ERP5
object can lead to adding subobjects as attributes of the new object, which
is completely undesirable. To handle this, it is important to delete the
sub-objects as the attributes for those migrated classes.

erp5_catalog: Refactor _bootstrap for Catalog Tool

Old Catalog Tool didn't have portal_type attribute, so while migrating
via synchronizeDynamicModule, after _bootstrap, we expect the tool to
have a portal_type to finalize migration.

This step is now being done only at the end of _bootstrap after we
change the classes for portal_catalog and its sub-objects.

And, changes to improve performance while dynamic migration.

XXX: Still at this point we are not doing the same thing with
sub-objects of catalog tool and wait till business template
installation.

erp5_catalog: Update attributes of the portal_catalog object after migration
parent e98c2e06
...@@ -24,6 +24,19 @@ def changeObjectClass(self, object_id, new_class): ...@@ -24,6 +24,19 @@ def changeObjectClass(self, object_id, new_class):
new_obj.__dict__.update(old_obj.__dict__) new_obj.__dict__.update(old_obj.__dict__)
if new_class.__module__ == 'erp5.portal_type': if new_class.__module__ == 'erp5.portal_type':
new_obj.portal_type = new_class.__name__ new_obj.portal_type = new_class.__name__
# Workaround for new object which inherit from Folder or XMLobject
# For the CMF objects, the sub-objects acts as attributes, but for the objects
# inside they should be inside the HBTree to be called subobject.
# This patch adds the objects as sub-objects for those erp5 objects
if new_obj._getOb.__module__ == 'Products.ERP5Type.Core.Folder':
for obj in old_obj.objectValues():
# We don't want to keep the sub-objects as attributes for any objects
# specifically for objects which we are shifting to dynamic portal_type
# classes, cause if we edit or delete object, it would only delete the
# object and not remove the attribute, which leads to error if we try
# adding object with same id.
delattr(new_obj, obj.id)
  • I believe this will fail when old_obj inherits from something more advanced than OFS.Folder. Also, I suspect it may leave garbage behind if old_obj is an ordered folder. We may not care, I do not know. Maybe it should be noted as an # XXX if not tested against.

Please register or sign in to reply
  • The usage of changeObjectClass is only for Catalog. I agree that it'll fail in case something more advanced uses it. I'll add # XXX for now on this change.

Please register or sign in to reply
new_obj._setOb(obj.id, obj)
self._setOb(object_id, new_obj) self._setOb(object_id, new_obj)
if self._delOb.__module__ == 'OFS.ObjectManager': if self._delOb.__module__ == 'OFS.ObjectManager':
# Workaround OFS updating '_objects' in _[ds]etObject instead of _[ds]etOb # Workaround OFS updating '_objects' in _[ds]etObject instead of _[ds]etOb
......
...@@ -342,6 +342,78 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -342,6 +342,78 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
, 'manage_schema') , 'manage_schema')
manage_schema = DTMLFile('dtml/manageSchema', globals()) manage_schema = DTMLFile('dtml/manageSchema', globals())
def _isBootstrapRequired(self):
return True
def _bootstrap(self):
# Get erp5 site
parent = self.aq_parent
portal_types = parent.portal_types
portal_property_sheets = parent.portal_property_sheets
from Products.ERP5.ERP5Site import ERP5Generator
ERP5Generator.bootstrap(portal_types, 'erp5_core', 'PortalTypeTemplateItem', (
'Catalog',
'Catalog Tool',
'SQL Method',
'Python Script'
))
ERP5Generator.bootstrap(portal_property_sheets, 'erp5_core', 'PropertySheetTemplateItem', (
'Catalog',
'CatalogTool',
'SQLMethod',
'PythonScript',
'CatalogFilter'
))
# We need ERP5 Form portal_type to exist during migration we would be
# indexing some ERP5 Form objects.
ERP5Generator.bootstrap(portal_types, 'erp5_hal_json_style', 'PortalTypeTemplateItem', (
'ERP5 Form',
))
import erp5
from Products.ERP5.Extensions.CheckPortalTypes import changeObjectClass
# Get all dynamic classes from portal_type
catalog_tool_class = getattr(erp5.portal_type, 'Catalog Tool')
catalog_class = getattr(erp5.portal_type, 'Catalog')
sql_class = getattr(erp5.portal_type, 'SQL Method')
script_class = getattr(erp5.portal_type, 'Python Script')
if not catalog_tool_class:
LOG('OldCatalogTool', WARNING, "Portal Type Catalog Tool doesn't exist")
return
# Change classes for all object inside catalog and catalog_tool
for obj in self.objectValues():
filter_dict = obj.filter_dict
for method in obj.objectValues():
if method.meta_type == 'Z SQL Method':
new_method = changeObjectClass(obj, method.id, sql_class)
elif method.meta_type == 'Script (Python)':
new_method = changeObjectClass(obj, method.id, script_class)
else:
LOG('Catalog Migration', WARNING, '''Subobject %s is not of meta_type \
Z SQL Method or Script(Python)'''%method.id)
return
# Migrate filter_dict and keep them as properties for the methods
new_method_id = new_method.id
if new_method_id in filter_dict:
filter_ = filter_dict[new_method_id]
new_method.setFiltered(filter_['filtered'])
new_method.setTypeList(filter_['type'])
new_method.setExpressionCacheKeyList(filter_['expression_cache_key'])
new_method.setExpression(filter_['expression'])
new_method.setExpressionInstance(filter_['expression_instance'])
# Delete filter_dict before migration of catalog object(s)
del obj.filter_dict
changeObjectClass(self, obj.id, catalog_class)
changeObjectClass(parent, self.id, catalog_tool_class)
# Update some required attributes to the portal_catalog object
parent.portal_catalog.default_erp5_catalog_id = self.default_sql_catalog_id
security.declarePublic('getPreferredSQLCatalogId') security.declarePublic('getPreferredSQLCatalogId')
def getPreferredSQLCatalogId(self, id=None): def getPreferredSQLCatalogId(self, id=None):
""" """
......
...@@ -327,13 +327,23 @@ def synchronizeDynamicModules(context, force=False): ...@@ -327,13 +327,23 @@ def synchronizeDynamicModules(context, force=False):
from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool
from Products.ERP5Type.Tool.TypesTool import TypesTool from Products.ERP5Type.Tool.TypesTool import TypesTool
from Products.ERP5Type.Tool.ComponentTool import ComponentTool from Products.ERP5Type.Tool.ComponentTool import ComponentTool
from Products.ERP5Catalog.Tool.ERP5CatalogTool import ERP5CatalogTool
try: try:
for tool_class in TypesTool, PropertySheetTool, ComponentTool: for tool_class in TypesTool, PropertySheetTool, ComponentTool, ERP5CatalogTool:
# if the instance has no property sheet tool, or incomplete # if the instance has no property sheet tool, or incomplete
# property sheets, we need to import some data to bootstrap # property sheets, we need to import some data to bootstrap
# (only likely to happen on the first run ever) # (only likely to happen on the first run ever)
tool_id = tool_class.id tool_id = tool_class.id
tool = getattr(portal, tool_id, None) tool = getattr(portal, tool_id, None)
if tool_class == ERP5CatalogTool and tool is None:
Please register or sign in to reply
  • Those are two separate conditions. The first one with if tool_class == ERP5CatalogTool and tool is None cares for tool_class to be just in case ERP5CatalogTool.

Please register or sign in to reply
Please register or sign in to reply
# Wait till we find that SQL Catalog Tool is installed
# Simpy said, we don't want ERP5 Catalog Tool to be installed
# from here. So, we come to 2 cases:
# 1. Running ERP5Site with sql catalog_tool : In that case, we end up
# running _bootstrap from here, leading to migration.
# 2. New ERP5Site : In this case, we don't do anything here, cause
# the catalog_tool would be ERP5CatalogTool, so this would just pass.
continue
if tool is None: if tool is None:
tool = tool_class() tool = tool_class()
portal._setObject(tool_id, tool, set_owner=False, portal._setObject(tool_id, tool, set_owner=False,
......
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