From ead87b6a51a251eb8989e950f543af32f91f40b0 Mon Sep 17 00:00:00 2001
From: Julien Muchembled <jm@nexedi.com>
Date: Fri, 2 Apr 2010 16:44:25 +0000
Subject: [PATCH] composition: make objectValues return original objects
 instead of temporary copies

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@34285 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5/mixin/composition.py        | 48 ++++++++++++------------
 product/ERP5/tests/testTradeModelLine.py |  4 --
 2 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/product/ERP5/mixin/composition.py b/product/ERP5/mixin/composition.py
index 1a4c45c9c4..98ae24fc0c 100644
--- a/product/ERP5/mixin/composition.py
+++ b/product/ERP5/mixin/composition.py
@@ -31,6 +31,7 @@ from AccessControl import ClassSecurityInfo
 from Acquisition import aq_base
 from Products.ERP5Type import Permissions
 from Products.ERP5Type.Cache import transactional_cached
+from Products.ERP5Type.Utils import sortValueList
 from Products.ERP5.Document.Predicate import Predicate
 from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
 
@@ -78,7 +79,6 @@ def _getEffectiveModel(self, start_date=None, stop_date=None):
 def _findPredicateList(*container_list):
   predicate_list = []
   reference_dict = {}
-  line_count = 0
   for container in container_list:
     for ob in container.contentValues():
       if isinstance(ob, Predicate):
@@ -89,9 +89,7 @@ def _findPredicateList(*container_list):
           if reference in reference_set:
             continue
           reference_set.add(reference)
-        id = str(line_count)
-        line_count += 1
-        predicate_list.append(aq_base(ob.asContext(id=id)))
+        predicate_list.append(ob)
   return predicate_list
 
 
@@ -101,20 +99,13 @@ class asComposedDocument(object):
   The returned value is a temporary copy of the given object. The list of all
   effective models (specialise values) is stored in a private attribute.
   Collecting predicates (from effective models) is done lazily. Predicates can
-  be accessed through standard Folder API (ex: contentValues).
+  be accessed through contentValues/objectValues.
   """
 
   def __new__(cls, orig_self):
-    if '_effective_model_list' in orig_self.__dict__:
-      assert False, "not used yet (remove this line if needed)"
-      return orig_self # if asComposedDocument is called on a composed
-                       # document after any access to its subobjects
     self = orig_self.asContext()
-    self._initBTrees()
     base_class = self.__class__
-    # this allows to intercept first access to '_folder_handler'
-    self.__class__ = type(base_class.__name__, (cls, base_class),
-                          {'__module__': base_class.__module__})
+    self.__class__ = type(base_class.__name__, (cls, base_class), {})
     self._effective_model_list = orig_self._findEffectiveSpecialiseValueList()
     return self
 
@@ -125,20 +116,29 @@ class asComposedDocument(object):
 
   def asComposedDocument(self):
     assert False, "not used yet (remove this line if needed)"
-    return self # if asComposedDocument is called on a composed
-                # document before any access to its subobjects
+    return self
 
   @property
   def _folder_handler(self):
-    # restore the original class
-    # because we don't need to hook _folder_handler anymore
-    self.__class__ = self.__class__.__bases__[1]
-    # we filter out objects without any subobject to make the cache of
-    # '_findPredicateList' useful. Otherwise, the key would be always different
-    # (starting with 'orig_self').
-    for ob in _findPredicateList(*filter(len, self._effective_model_list)):
-      self._setOb(ob.id, ob)
-    return self._folder_handler
+    assert False
+
+  def __getattr__(self, name):
+    raise AttributeError(name)
+
+  def objectValues(self, spec=None, meta_type=None, portal_type=None,
+                   sort_on=None, sort_order=None, checked_permission=None,
+                   **kw):
+    assert spec is meta_type is checked_permission is None, "not useful yet"
+    object_list = getattr(aq_base(self), '_predicate_list', None)
+    if object_list is None:
+      object_list = _findPredicateList(*filter(len, self._effective_model_list))
+      self._predicate_list = object_list
+    if portal_type is not None:
+      if isinstance(portal_type, str):
+        portal_type = (portal_type,)
+      object_list = filter(lambda x: x.getPortalType() in portal_type,
+                           object_list)
+    return sortValueList(object_list, sort_on, sort_order, **kw)
 
 
 class CompositionMixin:
diff --git a/product/ERP5/tests/testTradeModelLine.py b/product/ERP5/tests/testTradeModelLine.py
index 09af5021fe..1f327a2cd0 100644
--- a/product/ERP5/tests/testTradeModelLine.py
+++ b/product/ERP5/tests/testTradeModelLine.py
@@ -2476,8 +2476,6 @@ class TestTradeModelLine(TestTradeModelLineMixin):
 
     # change target level to `movement`.
     tax.edit(target_level=TARGET_LEVEL_MOVEMENT)
-    transaction.commit() # flush transactional cache
-
     amount_list = trade_condition.getAggregatedAmountList(order)
     self.assertEqual(2, len(amount_list))
     self.assertEqual(1,
@@ -2578,7 +2576,6 @@ return current_movement
     extra_fee_a.edit(target_level=TARGET_LEVEL_DELIVERY)
     extra_fee_b.edit(target_level=TARGET_LEVEL_DELIVERY)
     tax.edit(target_level=TARGET_LEVEL_DELIVERY)
-    transaction.commit() # flush transactional cache
     amount_list = trade_condition.getAggregatedAmountList(order)
     self.assertEqual(4, len(amount_list))
     self.assertEqual(100 + 1 - 10 + 1500*0.05,
@@ -2637,7 +2634,6 @@ return current_movement
 
     # change tax trade model line to `movement` level
     tax.edit(target_level=TARGET_LEVEL_MOVEMENT)
-    transaction.commit() # flush transactional cache
 
     def getTotalAmount(amount_list):
       result = 0
-- 
2.30.9