0011492: activate advanced search (search in lead relations)
authorPhilipp Schüle <p.schuele@metaways.de>
Mon, 14 Dec 2015 15:03:45 +0000 (16:03 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 3 Feb 2016 15:11:27 +0000 (16:11 +0100)
* generalized advanced search in query filter
* query search in Tasks now also searches in related leads
* fixes some typos
* adds some documentation to GroupSelect

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

Change-Id: I05d7744646072bd54e643f2c2e0eed83909fb0c1
Reviewed-on: http://gerrit.tine20.com/customers/2500
Tested-by: Jenkins CI (http://ci.tine20.com/)
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Crm/JsonTest.php
tests/tine20/Tasks/JsonTest.php
tine20/Crm/Model/LeadQueryFilter.php
tine20/Tasks/Model/TaskFilter.php
tine20/Tinebase/Backend/Sql/Filter/GroupSelect.php
tine20/Tinebase/Model/Filter/Abstract.php
tine20/Tinebase/Model/Filter/Query.php

index 23cb84f..b236c69 100644 (file)
@@ -24,7 +24,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      *
      * @var Crm_Frontend_Json
      */
-    protected $_instance;
+    protected $_instance = null;
     
     /**
      * fs controller
@@ -51,12 +51,23 @@ class Crm_JsonTest extends Crm_AbstractTest
     {
         parent::setUp();
         
-        $this->_instance = new Crm_Frontend_Json();
         $this->_fsController = Tinebase_FileSystem::getInstance();
         Crm_Controller_Lead::getInstance()->duplicateCheckFields(array());
     }
 
     /**
+     * @return Crm_Frontend_Json
+     */
+    protected function _getUit()
+    {
+        if ($this->_instance === null) {
+            $this->_instance = new Crm_Frontend_Json();
+        }
+
+        return new $this->_instance;
+    }
+
+    /**
      * Tears down the fixture
      * This method is called after a test is executed.
      *
@@ -85,7 +96,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testGetRegistryData()
     {
-        $registry = $this->_instance->getRegistryData();
+        $registry = $this->_getUit()->getRegistryData();
         
         $types = array('leadtypes', 'leadstates', 'leadsources');
         
@@ -118,7 +129,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testGetSettings()
     {
-        $result = $this->_instance->getSettings();
+        $result = $this->_getUit()->getSettings();
         
         $this->assertArrayHasKey('leadstates',  $result);
         $this->assertArrayHasKey('leadtypes',   $result);
@@ -136,7 +147,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testSaveSettings()
     {
-        $oldSettings = $this->_instance->getSettings();
+        $oldSettings = $this->_getUit()->getSettings();
         
         // change some settings
         $newSettings = $oldSettings;
@@ -145,11 +156,11 @@ class Crm_JsonTest extends Crm_AbstractTest
             'id' => 5,
             'leadsource' => 'Another Leadsource'
         );
-        $anotherResult = $this->_instance->saveSettings($newSettings);
+        $anotherResult = $this->_getUit()->saveSettings($newSettings);
         $this->assertEquals($newSettings, $anotherResult, 'new settings have not been saved');
         
         // reset original settings
-        $result = $this->_instance->saveSettings($oldSettings);
+        $result = $this->_getUit()->saveSettings($oldSettings);
         $this->assertEquals($result, $oldSettings, 'old settings have not been reset');
         
         // test Crm_Model_Config::getOptionById
@@ -164,9 +175,9 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testAddGetSearchDeleteLead()
     {
-        $savedLead = $this->_saveLead();
-        $getLead = $this->_instance->getLead($savedLead['id']);
-        $searchLeads = $this->_instance->searchLeads($this->_getLeadFilter(), '');
+        $savedLead = $this->saveLead();
+        $getLead = $this->_getUit()->getLead($savedLead['id']);
+        $searchLeads = $this->_getUit()->searchLeads($this->_getLeadFilter(), '');
         
         // test manual resolving of organizer in related_record and set it back for following tests
         for ($i = 0; $i < count($getLead['relations']); $i++) {
@@ -228,12 +239,12 @@ class Crm_JsonTest extends Crm_AbstractTest
         $this->assertEquals($this->_getProduct()->name, $relatedProduct['name'], 'product name does not match');
         
         // delete all
-        $this->_instance->deleteLeads($savedLead['id']);
+        $this->_getUit()->deleteLeads($savedLead['id']);
         Addressbook_Controller_Contact::getInstance()->delete($relatedContact['id']);
         Sales_Controller_Product::getInstance()->delete($relatedProduct['id']);
         
         // check if delete worked
-        $result = $this->_instance->searchLeads($this->_getLeadFilter(), '');
+        $result = $this->_getUit()->searchLeads($this->_getLeadFilter(), '');
         $this->assertEquals(0, $result['totalcount']);
         
         // check if linked task got removed as well
@@ -246,7 +257,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      * 
      * @return array
      */
-    protected function _saveLead()
+    public function saveLead()
     {
         $contact    = $this->_getContact();
         $task       = $this->_getTask();
@@ -267,7 +278,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         );
         $leadData['notes'] = array($note);
         
-        $savedLead = $this->_instance->saveLead($leadData);
+        $savedLead = $this->_getUit()->saveLead($leadData);
         return $savedLead;
     }
     
@@ -279,7 +290,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     public function testTagFilter()
     {
         $lead       = $this->_getLead();
-        $savedLead = $this->_instance->saveLead($lead->toArray());
+        $savedLead = $this->_getUit()->saveLead($lead->toArray());
         
         $sharedTagName = Tinebase_Record_Abstract::generateUID();
         $tag = new Tinebase_Model_Tag(array(
@@ -299,7 +310,7 @@ class Crm_JsonTest extends Crm_AbstractTest
             array('field' => 'tag',           'operator' => 'equals',       'value' => $tag->getId()),
         );
         
-        $result = $this->_instance->searchLeads($filter, array());
+        $result = $this->_getUit()->searchLeads($filter, array());
         $this->assertEquals(0, $result['totalcount'], 'Should not find the lead!');
     }    
     
@@ -311,7 +322,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     public function testSearchByBrokenFilter()
     {
         $filter = Zend_Json::decode('[{"field":"query","operator":"contains","value":"test"},{"field":"container_id","operator":"equals","value":{"path":"/"}},{"field":"contact","operator":"AND","value":[{"field":":id","operator":"equals","value":{"n_fn":"","n_fileas":"","org_name":"","container_id":"2576"}}]}]');
-        $result = $this->_instance->searchLeads($filter, array());
+        $result = $this->_getUit()->searchLeads($filter, array());
         $this->assertEquals(0, $result['totalcount']);
     }
     
@@ -330,16 +341,16 @@ class Crm_JsonTest extends Crm_AbstractTest
         $leadData['relations'] = array(
             array('type'  => 'PARTNER', 'related_record' => $savedContact->toArray()),
         );
-        $savedLead = $this->_instance->saveLead($leadData);
+        $savedLead = $this->_getUit()->saveLead($leadData);
         
         $savedLead['relations'] = array();
-        $savedLead = $this->_instance->saveLead($savedLead);
+        $savedLead = $this->_getUit()->saveLead($savedLead);
         $this->assertEquals(0, count($savedLead['relations']));
         
         $savedLead['relations'] = array(
             array('type'  => 'PARTNER', 'related_record' => $savedContact->toArray()),
         );
-        $savedLead = $this->_instance->saveLead($savedLead);
+        $savedLead = $this->_getUit()->saveLead($savedLead);
         
         $this->assertEquals(1, count($savedLead['relations']), 'Relation has not been added');
         $this->assertEquals($contact->n_fn, $savedLead['relations'][0]['related_record']['n_fn'], 'Contact name does not match');
@@ -360,7 +371,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         $leadData['relations'] = array(
             array('type'  => '', 'related_record' => $savedContact->toArray()),
         );
-        $savedLead = $this->_instance->saveLead($leadData);
+        $savedLead = $this->_getUit()->saveLead($leadData);
         
         $this->assertEquals(1, count($savedLead['relations']), 'Relation has not been added');
         $this->assertEquals('CUSTOMER', $savedLead['relations'][0]['type'], 'default type should be CUSTOMER');
@@ -374,7 +385,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testConcurrentRelationSetting()
     {
-        $leadData = $this->_instance->saveLead($this->_getLead()->toArray());
+        $leadData = $this->_getUit()->saveLead($this->_getLead()->toArray());
         $task = $this->_getTask();
         
         $taskJson = new Tasks_Frontend_Json();
@@ -396,14 +407,14 @@ class Crm_JsonTest extends Crm_AbstractTest
         $taskData['description'] = 1;
         $taskJson->saveTask($taskData);
         
-        $savedLead = $this->_instance->getLead($leadData['id']);
+        $savedLead = $this->_getUit()->getLead($leadData['id']);
         $savedLead['relations'][0]['related_record']['description'] = '2';
         $savedLead['relations'][0]['related_record']['due'] = '2012-10-18 12:54:33';
         
         // client may send wrong seq -> this should cause a concurrency conflict
         $savedLead['relations'][0]['related_record']['seq'] = 0;
         try {
-            $this->_instance->saveLead($savedLead);
+            $this->_getUit()->saveLead($savedLead);
             $this->fail('expected concurrency exception');
         } catch (Tinebase_Timemachine_Exception_ConcurrencyConflict $ttecc) {
             $this->assertEquals('concurrency conflict!', $ttecc->getMessage());
@@ -418,7 +429,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testConstraintsOtherSide()
     {
-        $leadData1 = $this->_instance->saveLead($this->_getLead(FALSE, FALSE)->toArray());
+        $leadData1 = $this->_getUit()->saveLead($this->_getLead(FALSE, FALSE)->toArray());
         $task = $this->_getTask();
         
         $taskJson = new Tasks_Frontend_Json();
@@ -438,7 +449,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         
         $taskData = $taskJson->saveTask($taskData);
         
-        $leadData2 = $this->_instance->saveLead($this->_getLead(FALSE, FALSE)->toArray());
+        $leadData2 = $this->_getUit()->saveLead($this->_getLead(FALSE, FALSE)->toArray());
         $taskData['relations'][] = array(
             'type'  => 'TASK',
             'own_model' => 'Tasks_Model_Task',
@@ -459,7 +470,7 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testOtherRecordConstraintsConfig()
     {
-        $leadData1 = $this->_instance->saveLead($this->_getLead(FALSE, FALSE)->toArray());
+        $leadData1 = $this->_getUit()->saveLead($this->_getLead(FALSE, FALSE)->toArray());
         $task = $this->_getTask();
         
         $taskJson = new Tasks_Frontend_Json();
@@ -481,7 +492,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         
         $taskData = $taskJson->saveTask($taskData);
         
-        $leadData2 = $this->_instance->saveLead($this->_getLead(FALSE, FALSE)->toArray());
+        $leadData2 = $this->_getUit()->saveLead($this->_getLead(FALSE, FALSE)->toArray());
         
         $leadData2['relations'] = array(
             array(
@@ -625,7 +636,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         }
         
         return new Crm_Model_Lead(array(
-            'lead_name'     => 'PHPUnit',
+            'lead_name'     => 'PHPUnit LEAD',
             'leadstate_id'  => 1,
             'leadtype_id'   => 1,
             'leadsource_id' => 1,
@@ -674,7 +685,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     public function testRelatedModlog()
     {
         // create lead with tag, customfield and related contacts
-        $savedLead = $this->_saveLead();
+        $savedLead = $this->saveLead();
         
         // change relations, customfields + tags
         $savedLead['tags'][] = array('name' => 'another tag', 'type' => Tinebase_Model_Tag::TYPE_PERSONAL);
@@ -687,7 +698,7 @@ class Crm_JsonTest extends Crm_AbstractTest
             }
         }
         $savedLead['customfields'][$this->_cfcName] = '5678';
-        $updatedLead = $this->_instance->saveLead($savedLead);
+        $updatedLead = $this->_getUit()->saveLead($savedLead);
         
         // check modlog + history
         $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getModifications('Crm', $updatedLead['id']);
@@ -732,7 +743,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         $lead = $this->_getLead()->toArray();
         $lead['attachments'] = array(array('tempFile' => $tempFile->toArray()));
         
-        $savedLead = $this->_instance->saveLead($lead);
+        $savedLead = $this->_getUit()->saveLead($lead);
         // add path to files to remove
         $this->_objects['paths'][] = Tinebase_FileSystem_RecordAttachments::getInstance()->getRecordAttachmentPath(new Crm_Model_Lead($savedLead, TRUE)) . '/' . $tempFile->name;
         
@@ -755,7 +766,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     public function testUpdateLeadWithAttachment()
     {
         $lead = $this->testCreateLeadWithAttachment();
-        $savedLead = $this->_instance->saveLead($lead);
+        $savedLead = $this->_getUit()->saveLead($lead);
         $this->assertTrue(isset($savedLead['attachments']), 'no attachments found');
         $this->assertEquals(1, count($savedLead['attachments']));
     }
@@ -770,7 +781,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         $lead = $this->testCreateLeadWithAttachment();
         $lead['attachments'] = array();
     
-        $savedLead = $this->_instance->saveLead($lead);
+        $savedLead = $this->_getUit()->saveLead($lead);
         $this->assertEquals(0, count($savedLead['attachments']));
         $this->assertFalse($this->_fsController->fileExists($this->_objects['paths'][0]));
     }
@@ -783,7 +794,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     public function testDeleteLeadWithAttachment()
     {
         $lead = $this->testCreateLeadWithAttachment();
-        $this->_instance->deleteLeads(array($lead['id']));
+        $this->_getUit()->deleteLeads(array($lead['id']));
         $this->assertFalse($this->_fsController->fileExists($this->_objects['paths'][0]));
     }
 
@@ -796,7 +807,7 @@ class Crm_JsonTest extends Crm_AbstractTest
     {
         $leadArray = $this->_getLead()->toArray();
         $leadArray['start'] = null;
-        $newLead = $this->_instance->saveLead($leadArray);
+        $newLead = $this->_getUit()->saveLead($leadArray);
         
         $this->assertContains(Tinebase_DateTime::now()->format('Y-m-d'), $newLead['start'], 'start should be set to now if missing');
     }
@@ -808,16 +819,16 @@ class Crm_JsonTest extends Crm_AbstractTest
      */
     public function testSortByLeadState()
     {
-        $this->_saveLead();
+        $this->saveLead();
         $lead2 = $this->_getLead()->toArray();  // open
         $lead2['leadstate_id'] = 2;             // contacted
-        $this->_instance->saveLead($lead2);
+        $this->_getUit()->saveLead($lead2);
         
         $sort = array(
             'sort' => 'leadstate_id',
             'dir' => 'ASC'
         );
-        $searchLeads = $this->_instance->searchLeads($this->_getLeadFilter(), $sort);
+        $searchLeads = $this->_getUit()->searchLeads($this->_getLeadFilter(), $sort);
         
         $this->assertEquals(2, $searchLeads['results'][0]['leadstate_id'], 'leadstate "contacted" should come first');
     }
@@ -831,11 +842,11 @@ class Crm_JsonTest extends Crm_AbstractTest
     {
         Tinebase_Core::getPreference()->setValue(Tinebase_Preference::ADVANCED_SEARCH, true);
         
-        $this->_saveLead();
+        $this->saveLead();
         $filter = array(
             array('field' => 'query',           'operator' => 'contains',       'value' => 'PHPUnit test product'),
         );
-        $searchLeads = $this->_instance->searchLeads($filter, '');
+        $searchLeads = $this->_getUit()->searchLeads($filter, '');
         $this->assertEquals(1, $searchLeads['totalcount']);
     }
 }
index e0d378a..4f318c0 100644 (file)
@@ -17,7 +17,7 @@ require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php'
 /**
  * Test class for Tasks_JsonTest
  */
-class Tasks_JsonTest extends PHPUnit_Framework_TestCase
+class Tasks_JsonTest extends TestCase
 {
     /**
      * Backend
@@ -46,16 +46,6 @@ class Tasks_JsonTest extends PHPUnit_Framework_TestCase
      * @var Zend_Mail_Transport_Abstract
      */
     protected $_smtpTransport = NULL;
-    
-    /**
-     * main function
-     *
-     */
-    public static function main()
-    {
-        $suite  = new PHPUnit_Framework_TestSuite('Tasks_JsonTest');
-        PHPUnit_TextUI_TestRunner::run($suite);
-    }
 
     /**
      * Sets up the fixture, for example, opens a network connection.
@@ -65,7 +55,7 @@ class Tasks_JsonTest extends PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+        parent::setUp();
         
         $this->_backend = new Tasks_Frontend_Json();
         $this->_smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SMTP, new Tinebase_Config_Struct())->toArray();
@@ -84,8 +74,10 @@ class Tasks_JsonTest extends PHPUnit_Framework_TestCase
             Tinebase_Config::getInstance()->set(Tinebase_Config::SMTP, $this->_smtpConfig);
             Tinebase_Smtp::setDefaultTransport($this->_smtpTransport);
         }
-        
-        Tinebase_TransactionManager::getInstance()->rollBack();
+
+        Tinebase_Core::getPreference()->setValue(Tinebase_Preference::ADVANCED_SEARCH, false);
+
+        parent::tearDown();
     }
     
     /**
@@ -460,5 +452,25 @@ class Tasks_JsonTest extends PHPUnit_Framework_TestCase
             'dir' => 'ASC',
         );
     }
-}
 
+    /**
+     * test advanced search
+     *
+     * @see 0011492: activate advanced search (search in lead relations)
+     */
+    public function testAdvancedSearch()
+    {
+        // create task with lead relation
+        $crmTests = new Crm_JsonTest();
+        $crmTests->saveLead();
+
+        // activate advanced search
+        Tinebase_Core::getPreference()->setValue(Tinebase_Preference::ADVANCED_SEARCH, true);
+
+        // search in lead
+        $result = $this->_backend->searchTasks(array(array(
+            'field' => 'query', 'operator' => 'contains', 'value' => 'PHPUnit LEAD'
+        )), array());
+        $this->assertEquals(1, $result['totalcount']);
+    }
+}
index 5c296e4..d488dc9 100644 (file)
@@ -39,49 +39,31 @@ class Crm_Model_LeadQueryFilter extends Tinebase_Model_Filter_Abstract
             array('field' => 'lead_name',   'operator' => 'contains', 'value' => $this->_value),
             array('field' => 'description', 'operator' => 'contains', 'value' => $this->_value),
             
-            // hack to supress custom stuff
+            // hack to suppress custom stuff
             array('field' => 'showClosed',  'operator' => 'equals',   'value' => TRUE),
         );
         
         $filter = new Crm_Model_LeadFilter($filterData, 'OR');
-        $this->_appendRelationFilter($filter);
+        $this->_advancedSearch($filter);
         
         Tinebase_Backend_Sql_Filter_FilterGroup::appendFilters($_select, $filter, $_backend);
     }
-    
+
     /**
      * append relation filter
-     * 
-     * @param Crm_Model_LeadFilter $filter
+     *
+     * @param Tinebase_Model_Filter_FilterGroup $filter
      */
-    protected function _appendRelationFilter($filter)
+    protected function _advancedSearch(Tinebase_Model_Filter_FilterGroup $filter)
     {
-        if (! Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false)) {
-            return;
-        }
-        
-        $relationsToSearchIn = array(
+        $relationFilter = $this->_getAdvancedSearchFilter('Crm_Model_Lead', array(
             'Addressbook_Model_Contact',
             'Sales_Model_Product',
             'Tasks_Model_Task'
-        );
-        $leadIds = array();
-        
-        foreach ($relationsToSearchIn as $relatedModel) {
-            $filterModel = $relatedModel . 'Filter';
-            $relatedFilter = new $filterModel(array(
-                array('field' => 'query',   'operator' => 'contains', 'value' => $this->_value),
-            ));
-            $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE);
-            
-            $relationFilter = new Tinebase_Model_RelationFilter(array(
-                array('field' => 'own_model',     'operator' => 'equals', 'value' => 'Crm_Model_Lead'),
-                array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel),
-                array('field' => 'related_id',    'operator' => 'in'    , 'value' => $relatedIds)
-            ));
-            $leadIds = array_merge($leadIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id);
+        ));
+
+        if ($relationFilter) {
+            $filter->addFilter($relationFilter);
         }
-        
-        $filter->addFilter(new Tinebase_Model_Filter_Id('id', 'in', $leadIds));
     }
 }
index 8561869..f71baa4 100644 (file)
@@ -39,7 +39,13 @@ class Tasks_Model_TaskFilter extends Tinebase_Model_Filter_FilterGroup
         'id'                   => array('filter' => 'Tinebase_Model_Filter_Id', 'options' => array('modelName' => 'Tasks_Model_Task')),
         'uid'                  => array('filter' => 'Tinebase_Model_Filter_Text'),
         'etag'                 => array('filter' => 'Tinebase_Model_Filter_Text'),
-        'query'                => array('filter' => 'Tinebase_Model_Filter_Query', 'options' => array('fields' => array('summary', 'description'))),
+        'query'                => array('filter' => 'Tinebase_Model_Filter_Query', 'options' => array(
+            'modelName' => 'Tasks_Model_Task',
+            'fields' => array('summary', 'description'),
+            'relatedModels' => array(
+                'Crm_Model_Lead',
+            )
+        )),
         'organizer'            => array('filter' => 'Tinebase_Model_Filter_User'),
         'status'               => array('filter' => 'Tinebase_Model_Filter_Text'),
         'due'                  => array('filter' => 'Tinebase_Model_Filter_DateTime'),
index 7d24e96..3f02965 100644 (file)
@@ -5,13 +5,23 @@
  * @package     Tinebase
  * @subpackage  Filter
  * @license     New BSD License
- * @copyright   Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2007-2015 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Cornelius Weiss <c.weiss@metaways.de>
  */
 
 /**
- * This object appends all contained filters at once concated by the concatenation
- * operator of the filtergroup, in order to archive nested filters.
+ * This object appends all contained filters at once concatenated by the concatenation
+ * operator of the filtergroup, in order to achieve nested filters.
+ *
+ * use it like this:
+ *
+ * $select1->where(COND1.1)
+ * $select1->where(COND1.2)
+ * $select2 = new Tinebase_Backend_Sql_Filter_GroupSelect($select1);
+ * $select2->where(COND2.1)
+ * $select2->appendWhere(Zend_Db_Select::SQL_OR);
+ *
+ * => (COND1.1 AND COND1.2) OR COND2.1
  * 
  * @package     Tinebase
  * @subpackage  Filter
@@ -63,7 +73,7 @@ class Tinebase_Backend_Sql_Filter_GroupSelect
      * 
      * @param string   $cond  The WHERE condition.
      * @param string   $value OPTIONAL A single value to quote into the condition.
-     * @param constant $type  OPTIONAL The type of the given value
+     * @param string $type  OPTIONAL The type of the given value
      * @return Zend_Db_Select This Zend_Db_Select object.
      */
     public function where($cond, $value = null, $type = null)
@@ -78,7 +88,7 @@ class Tinebase_Backend_Sql_Filter_GroupSelect
      *
      * @param string   $cond  The WHERE condition.
      * @param string   $value OPTIONAL A single value to quote into the condition.
-     * @param constant $type  OPTIONAL The type of the given value
+     * @param string $type  OPTIONAL The type of the given value
      * @return Zend_Db_Select This Zend_Db_Select object.
      */
     public function orWhere($cond, $value = null, $type = null)
index 68531e2..14d11ae 100644 (file)
@@ -371,10 +371,10 @@ abstract class Tinebase_Model_Filter_Abstract
         
         return $result;
     }
-    
+
     /**
      * replaces wildcards
-     * 
+     *
      * @param  string $value
      * @return string
      */
@@ -388,26 +388,68 @@ abstract class Tinebase_Model_Filter_Abstract
         } else {
             $returnValue = $this->_replaceWildcardsSingleValue($value);
         }
-        
+
         return $returnValue;
     }
-    
+
     /**
      * replaces wildcards of a single value
-     * 
+     *
      * @param  string $value
      * @return string
      */
     protected function _replaceWildcardsSingleValue($value)
     {
         $action = $this->_opSqlMap[$this->_operator];
-        
+
         // replace wildcards from user ()
         $returnValue = str_replace(array('*', '_'),  $this->_dbCommand->setDatabaseJokerCharacters(), $value);
-        
+
         // add wildcard to value according to operator
         $returnValue = str_replace('?', $returnValue, $action['wildcards']);
-        
+
         return $returnValue;
     }
+
+    /**
+     * append relation filter
+     *
+     * @param string $ownModel
+     * @param array $relationsToSearchIn
+     * @return Tinebase_Model_Filter_Id
+     */
+    protected function _getAdvancedSearchFilter($ownModel = null, $relationsToSearchIn = null)
+    {
+        if (  Tinebase_Core::get('ADVANCED_SEARCHING') ||
+            ! Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false) ||
+              empty($relationsToSearchIn))
+        {
+            return null;
+        }
+
+        $ownIds = array();
+        foreach ((array) $relationsToSearchIn as $relatedModel) {
+            $filterModel = $relatedModel . 'Filter';
+            // prevent recursion here
+            // TODO find a better way for this, maybe we could pass this an option to all filters in filter model
+            Tinebase_Core::set('ADVANCED_SEARCHING', true);
+            $relatedFilter = new $filterModel(array(
+                array('field' => 'query',   'operator' => 'contains', 'value' => $this->_value),
+            ));
+            $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE);
+            Tinebase_Core::set('ADVANCED_SEARCHING', false);
+
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
+                . ' Found ' . count($relatedIds) . ' related ids');
+
+            $relationFilter = new Tinebase_Model_RelationFilter(array(
+                array('field' => 'own_model',     'operator' => 'equals', 'value' => $ownModel),
+                array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel),
+                array('field' => 'related_id',    'operator' => 'in'    , 'value' => $relatedIds)
+            ));
+            $ownIds = array_merge($ownIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id);
+        }
+
+        return new Tinebase_Model_Filter_Id('id', 'in', $ownIds);
+    }
 }
index 3d5287f..f5e6787 100644 (file)
@@ -5,7 +5,7 @@
  * @package     Tinebase
  * @subpackage  Filter
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2007-2015 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Cornelius Weiss <c.weiss@metaways.de>
  */
 
@@ -119,5 +119,18 @@ class Tinebase_Model_Filter_Query extends Tinebase_Model_Filter_Abstract
              default:
                  throw new Tinebase_Exception_InvalidArgument('Operator not defined: ' . $this->_operator);
          }
-     }
-}
\ No newline at end of file
+
+        // append advanced search filter if configured
+        if (isset($this->_options['relatedModels']) && isset($this->_options['modelName'])) {
+            $relationFilter = $this->_getAdvancedSearchFilter($this->_options['modelName'], $this->_options['relatedModels']);
+            if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+                . ' Got relation filter: '
+                . ($relationFilter instanceof Tinebase_Model_Filter_Abstract ? print_r($relationFilter->toArray(), true) : ''));
+            if ($relationFilter) {
+                $relationSelect = new Tinebase_Backend_Sql_Filter_GroupSelect($_select);
+                $relationFilter->appendFilterSql($relationSelect, $_backend);
+                $relationSelect->appendWhere(Zend_Db_Select::SQL_OR);
+            }
+        }
+    }
+}