0009774: allow to define which relations should be fetched on search
authorAlexander Stintzing <a.stintzing@metaways.de>
Thu, 13 Mar 2014 16:50:40 +0000 (17:50 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 10 Sep 2014 11:06:25 +0000 (13:06 +0200)
if searching for records having many relations, it's very expensive.
So we need a parameter which allows to fetch relations with a special
related model.

https://forge.tine20.org/mantisbt/view.php?id=9774

Change-Id: I77ff8ed082b2481b7f8c32159e91ef3d7020ab44
Reviewed-on: http://gerrit.tine20.com/customers/472
Tested-by: Jenkins CI (http://ci.tine20.com/)
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
Tested-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Crm/JsonTest.php
tests/tine20/Tinebase/Relation/RelationTest.php
tine20/Crm/Controller/Lead.php
tine20/Crm/Frontend/Json.php
tine20/Tinebase/Controller/Record/Abstract.php
tine20/Tinebase/Frontend/Json/Abstract.php
tine20/Tinebase/Relation/Backend/Sql.php
tine20/Tinebase/Relations.php

index abdd21b..8593e1c 100644 (file)
@@ -172,8 +172,23 @@ class Crm_JsonTest extends Crm_AbstractTest
         $this->assertEquals($getLead['description'], $searchLeads['results'][0]['description']);
         $this->assertEquals(200, $searchLeads['results'][0]['turnover'], 'turnover has not been calculated using product prices');
         $this->assertEquals($searchLeads['results'][0]['turnover']*$getLead['probability']/100, $searchLeads['results'][0]['probableTurnover']);
-        $this->assertTrue(count($searchLeads['results'][0]['relations']) == 3, 'did not get all relations');
-
+        // now we need 2 relations here (frontend search shall return relations with related_model Addressbook_Model_Contact or Sales_Model_Product
+        $this->assertEquals(2, count($searchLeads['results'][0]['relations']), 'did not get all relations');
+        
+        foreach($getLead['relations'] as $rel) {
+            if ($rel['type'] == 'TASK') {
+                $relatedTask = $rel['related_record'];
+            }
+        }
+        
+        $this->assertEquals($this->_getTask()->summary, $relatedTask['summary'], 'task summary does not match');
+        $defaultTaskContainerId = Tinebase_Core::getPreference('Tasks')->getValue(Tasks_Preference::DEFAULTTASKLIST);
+        $this->assertEquals($defaultTaskContainerId, $relatedTask['container_id']);
+        $this->assertTrue(isset($relatedTask['alarms']) && count($relatedTask['alarms']) === 1, 'alarm missing in related task: ' . print_r($relatedTask, TRUE));
+        
+        $relatedTaskId = $relatedTask['id'];
+        $relatedTask = NULL;
+        
         // get related records and check relations
         foreach ($searchLeads['results'][0]['relations'] as $relation) {
             switch ($relation['type']) {
@@ -193,11 +208,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         $this->assertTrue(isset($relatedContact), 'contact not found');
         $this->assertEquals($this->_getContact()->n_fn, $relatedContact['n_fn'], 'contact name does not match');
         
-        $this->assertTrue(isset($relatedTask), 'task not found');
-        $this->assertEquals($this->_getTask()->summary, $relatedTask['summary'], 'task summary does not match');
-        $defaultTaskContainerId = Tinebase_Core::getPreference('Tasks')->getValue(Tasks_Preference::DEFAULTTASKLIST);
-        $this->assertEquals($defaultTaskContainerId, $relatedTask['container_id']);
-        $this->assertTrue(isset($relatedTask['alarms']) && count($relatedTask['alarms']) === 1, 'alarm missing in related task: ' . print_r($relatedTask, TRUE));
+        $this->assertFalse(is_array($relatedTask), 'task must not be found');
         
         $this->assertTrue(isset($relatedProduct), 'product not found');
         $this->assertEquals($this->_getProduct()->name, $relatedProduct['name'], 'product name does not match');
@@ -213,7 +224,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         
         // check if linked task got removed as well
         $this->setExpectedException('Tinebase_Exception_NotFound');
-        Tasks_Controller_Task::getInstance()->get($relatedTask['id']);
+        Tasks_Controller_Task::getInstance()->get($relatedTaskId);
     }
     
     /**
index ad58e87..264a210 100644 (file)
@@ -161,7 +161,7 @@ class Tinebase_Relation_RelationTest extends TestCase
      */
     public function testGetRelationsWithRelatedModel()
     {
-        $relations = $this->_object->getMultipleRelations($this->_crmId['model'], $this->_crmId['backend'], array($this->_crmId['id']), NULL, array(), FALSE, 'Addressbook_Model_Contact');
+        $relations = $this->_object->getMultipleRelations($this->_crmId['model'], $this->_crmId['backend'], array($this->_crmId['id']), NULL, array(), FALSE, array('Addressbook_Model_Contact'));
         $this->assertEquals(1, count($relations));
         $fr = $relations[0];
         $this->assertEquals(1, $fr->count());
index 707099d..1c3534c 100644 (file)
@@ -88,8 +88,10 @@ class Crm_Controller_Lead extends Tinebase_Controller_Record_Abstract
                 $this->_modelName, 
                 $this->_backend->getType(), 
                 $leads->getId(), 
-                NULL, 
-                array('CUSTOMER', 'PARTNER', 'TASK', 'RESPONSIBLE', 'PRODUCT')
+                NULL,
+                array('CUSTOMER', 'PARTNER', 'TASK', 'RESPONSIBLE', 'PRODUCT'),
+                FALSE,
+                $_getRelations
             ));
         }
         
index 247f8ec..91c8740 100644 (file)
@@ -48,7 +48,7 @@ class Crm_Frontend_Json extends Tinebase_Frontend_Json_Abstract
      */
     public function searchLeads($filter, $paging)
     {
-        $result = $this->_search($filter, $paging, $this->_controller, 'Crm_Model_LeadFilter', TRUE);
+        $result = $this->_search($filter, $paging, $this->_controller, 'Crm_Model_LeadFilter', array('Addressbook_Model_Contact', 'Sales_Model_Product'));
         
         // add totalcounts of leadstates/leadsources/leadtypes
         $result['totalleadstates'] = $result['totalcount']['leadstates'];
index d634df0..483d54f 100644 (file)
@@ -185,7 +185,7 @@ abstract class Tinebase_Controller_Record_Abstract
      *
      * @param Tinebase_Model_Filter_FilterGroup|optional $_filter
      * @param Tinebase_Model_Pagination|optional $_pagination
-     * @param boolean $_getRelations
+     * @param boolean|array $_getRelations
      * @param boolean $_onlyIds
      * @param string $_action for right/acl check
      * @return Tinebase_Record_RecordSet|array
@@ -200,7 +200,11 @@ abstract class Tinebase_Controller_Record_Abstract
 
         if (! $_onlyIds) {
             if ($_getRelations) {
-                $result->setByIndices('relations', Tinebase_Relations::getInstance()->getMultipleRelations($this->_modelName, $this->_getBackendType(), $result->getId()));
+                // if getRelations is true, all relations should be fetched
+                if ($_getRelations === TRUE) {
+                    $_getRelations = NULL;
+                }
+                $result->setByIndices('relations', Tinebase_Relations::getInstance()->getMultipleRelations($this->_modelName, $this->_getBackendType(), $result->getId(), NULL, array(), FALSE, $_getRelations));
             }
             if ($this->resolveCustomfields()) {
                 Tinebase_CustomField::getInstance()->resolveMultipleCustomfields($result);
index 6284c37..7928f2b 100644 (file)
@@ -231,7 +231,7 @@ abstract class Tinebase_Frontend_Json_Abstract extends Tinebase_Frontend_Abstrac
      * @param string|array                        $_paging json encoded / array
      * @param Tinebase_Controller_SearchInterface $_controller the record controller
      * @param string                              $_filterModel the class name of the filter model to use
-     * @param bool                                $_getRelations
+     * @param bool|array                          $_getRelations
      * @param string                              $_totalCountMethod
      * @return array
      */
index dd5461e..e37eb6a 100644 (file)
@@ -188,10 +188,10 @@ class Tinebase_Relation_Backend_Sql
      * @param  string       $_degree        only return relations of given degree
      * @param  array        $_type          only return relations of given type
      * @param  boolean      $_returnAll     gets all relations (default: only get not deleted/broken relations)
-     * @param  string       $_relatedModel  only return relations having this related model
+     * @param  array        $_relatedModels  only return relations having this related model
      * @return Tinebase_Record_RecordSet of Tinebase_Model_Relation
      */
-    public function getAllRelations($_model, $_backend, $_id, $_degree = NULL, array $_type = array(), $_returnAll = false, $_relatedModel = NULL)
+    public function getAllRelations($_model, $_backend, $_id, $_degree = NULL, array $_type = array(), $_returnAll = false, $_relatedModels = NULL)
     {
         $_id = $_id ? (array)$_id : array('');
         $where = array(
@@ -200,8 +200,8 @@ class Tinebase_Relation_Backend_Sql
             $this->_db->quoteInto($this->_db->quoteIdentifier('own_id') .' IN (?)' , $_id),
         );
         
-        if ($_relatedModel) {
-            $where[] = $this->_db->quoteInto($this->_db->quoteIdentifier('related_model') .' = ?', $_relatedModel);
+        if (is_array($_relatedModels) && ! empty($_relatedModels)) {
+            $where[] = $this->_db->quoteInto($this->_db->quoteIdentifier('related_model') .' IN (?)', $_relatedModels);
         }
         
         if (!$_returnAll) {
index ca92db1..8a015d9 100644 (file)
@@ -156,16 +156,16 @@ class Tinebase_Relations
      * @param  string       $_degree        only return relations of given degree
      * @param  array        $_type          only return relations of given type
      * @param  bool         $_ignoreACL     get relations without checking permissions
-     * @param  string       $_relatedModel  only return relations having this related model
+     * @param  array        $_relatedModels only return relations having this related models
      * @return Tinebase_Record_RecordSet of Tinebase_Model_Relation
      */
-    public function getRelations($_model, $_backend, $_id, $_degree = NULL, array $_type = array(), $_ignoreACL = FALSE, $_relatedModel = NULL)
+    public function getRelations($_model, $_backend, $_id, $_degree = NULL, array $_type = array(), $_ignoreACL = FALSE, $_relatedModels = NULL)
     {
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  model: '$_model' backend: '$_backend' " 
             // . 'ids: ' . print_r((array)$_id, true)
         );
-    
-        $result = $this->_backend->getAllRelations($_model, $_backend, $_id, $_degree, $_type, FALSE, $_relatedModel);
+        
+        $result = $this->_backend->getAllRelations($_model, $_backend, $_id, $_degree, $_type, FALSE, $_relatedModels);
         $this->resolveAppRecords($result, $_ignoreACL);
         
         return $result;
@@ -180,10 +180,10 @@ class Tinebase_Relations
      * @param  string $_degree        only return relations of given degree
      * @param  array  $_type          only return relations of given type
      * @param  bool   $_ignoreACL     get relations without checking permissions
-     * @param  string $_relatedModel  only return relations having this related model
+     * @param  array  $_relatedModels only return relations having this related model
      * @return array  key from $_ids => Tinebase_Record_RecordSet of Tinebase_Model_Relation
      */
-    public function getMultipleRelations($_model, $_backend, $_ids, $_degree = NULL, array $_type = array(), $_ignoreACL = FALSE, $_relatedModel = NULL)
+    public function getMultipleRelations($_model, $_backend, $_ids, $_degree = NULL, array $_type = array(), $_ignoreACL = FALSE, $_relatedModels = NULL)
     {
         // prepare a record set for each given id
         $result = array();
@@ -192,7 +192,7 @@ class Tinebase_Relations
         }
         
         // fetch all relations in a single set
-        $relations = $this->getRelations($_model, $_backend, $_ids, $_degree, $_type, $_ignoreACL, $_relatedModel);
+        $relations = $this->getRelations($_model, $_backend, $_ids, $_degree, $_type, $_ignoreACL, $_relatedModels);
         
         // sort relations into corrensponding sets
         foreach ($relations as $relation) {