diff --git a/product/ERP5Type/Interactor.py b/product/ERP5Type/Interactor.py new file mode 100644 index 0000000000000000000000000000000000000000..4df865f1d3e2f56facfdc26e3cfcbb6ae687333b --- /dev/null +++ b/product/ERP5Type/Interactor.py @@ -0,0 +1,148 @@ +from Products.ERP5Type.Accessor.Accessor import Accessor as Method +from Products.ERP5Type.Base import _aq_reset + +""" + Current implementation uses callable objects. + Using decorator would be more modern and consistent with + recent evolution of python. But we have 2.3 ERP5 users + so we should, at least, provide both implementations. + + Code structure should be changed so that Interactors + because a new "type" of ERP5 class such Document + with a modular plugin structure. + + TODO: multiple instances of interactors could + use different parameters. This way, interactions + can be defined on "instances" or can be + made generic. +""" + + +class InteractorMethodCall: + + def __init__(self, method, instance, *args, **kw): + self.instance = instance + self.args = args + self.kw = kw + self.method = method + + def __call__(self): + return self.method(self.instance, *self.args, **self.kw) + +class InteractorMethod(Method): + + def __init__(self, method): + self.after_action_list = [] + self.before_action_list = [] + self.method = method + self.func_code = method.func_code + self.func_defaults = method.func_defaults + + def registerBeforeAction(self, action, args, kw): + self.after_action_list.append((action, args, kw)) + + def registerAfterAction(self, action, args, kw): + self.after_action_list.append((action, args, kw)) + + def __call__(self, instance, *args, **kw): + method_call_object = InteractorMethodCall(self.method, instance, *args, **kw) + for action, args, kw in self.before_action_list: + action(method_call_object, *args, **kw) + result = method_call_object() + for action, args, kw in self.after_action_list: + action(method_call_object, *args, **kw) + return result + +class InteractorSource: + + def __init__(self, method): + """ + Register method + """ + self.method = method + + def doAfter(self, action, *args, **kw): + """ + """ + im_class = self.method.im_class + if not isinstance(self.method, InteractorMethod): + # Turn this into an InteractorMethod + interactor_method = InteractorMethod(self.method) + setattr(im_class, self.method.__name__, interactor_method) + self.method = interactor_method + # Register the action + self.method.registerAfterAction(action, args, kw) + +class Interactor: + def install(self): + raise NotImplementedError + + def uninstall(self): + raise NotImplementedError + + # Interaction implementation + def on(self, method): + """ + Parameters may hold predicates ? + no need - use InteractorMethodCall and decide on action + """ + return InteractorSource(method) + +class AqDynamicInteractor(Interactor): + + def install(self): + """ + Installs interactions + """ + from Products.ERP5.Interaction import InteractionDefinition + self.on(InteractionDefinition.setProperties).doAfter(self.resetAqDynamic, 1, 2, toto="foo") + self.on(InteractionDefinition.addVariable).doAfter(self.resetAqDynamic, 1, 2, toto="foo") + + def uninstall(self): + """ + Uninstall interactions + """ + + # Interaction example + def resetAqDynamic(self, method_call_object, a, b, toto=None): + """ + Reset _aq_dynamic + """ + _aq_reset() + +class FieldValueInteractor(Interactor): + + def install(self): + """ + Installs interactions + """ + from Products.Formulator.Field import ZMIField + self.on(ZMIField.manage_edit).doAfter(self.purgeFieldValueCache) + + def uninstall(self): + """ + Uninstall interactions + """ + + def purgeFieldValueCache(self, method_call_object): + """ + """ + # here call something + + +class TypeInteractorExample(Interactor): + def __init__(self, portal_type): + self.portal_type = portal_type + + def install(self): + from Products.CMFCore.TypesTool import TypesTool + self.on(TypesTool.manage_edit).doAfter(self.doSomething) + + def doSomething(self, method_call_object): + if self.portal_type == method_call_object.instance.portal_type: + pass + # do whatever + + +test = AqDynamicInteractor() +test.install() \ No newline at end of file