0011172: optimize getGroupmemberships in Principalbackend
[tine20] / tine20 / Tinebase / Container.php
index 2736966..443e812 100644 (file)
@@ -653,9 +653,10 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
      * @param  String            $_accountId
      * @param  Array|String      $_grant
      * @param  String            $_aclTableName
+     * @param  bool              $_andGrants
      * @return void
      */
-    public static function addGrantsSql($_select, $_accountId, $_grant, $_aclTableName = 'container_acl')
+    public static function addGrantsSql($_select, $_accountId, $_grant, $_aclTableName = 'container_acl', $_andGrants = FALSE, $joinCallBack = NULL)
     {
         $accountId = $_accountId instanceof Tinebase_Record_Abstract
             ? $_accountId->getId()
@@ -665,10 +666,7 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
         
         $grants = is_array($_grant) ? $_grant : array($_grant);
         
-        // admin grant includes all other grants
-        if (! in_array(Tinebase_Model_Grants::GRANT_ADMIN, $grants)) {
-            $grants[] = Tinebase_Model_Grants::GRANT_ADMIN;
-        }
+
 
         $groupMemberships   = Tinebase_Group::getInstance()->getGroupMemberships($accountId);
         
@@ -690,12 +688,29 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
             // @todo fetch wildcard from specific db adapter
             $grants = str_replace('*', '%', $grants);
         
-            $quotedGrant   = $db->quoteIdentifier("{$_aclTableName}.account_grant");
-            
+            $quotedGrant   = $db->quoteIdentifier($_aclTableName . '.account_grant');
+
+            $iteration = 0;
             $grantsSelect = new Tinebase_Backend_Sql_Filter_GroupSelect($_select);
             foreach ($grants as $grant) {
-                $grantsSelect->orWhere("{$quotedGrant} LIKE ?", $grant);
+                if ($_andGrants) {
+                    if ($iteration > 0) {
+                        $callbackIdentifier = call_user_func($joinCallBack, $_select, $iteration);
+                        $grantsSelect->where($db->quoteIdentifier($callbackIdentifier . '.account_grant') . ' LIKE ?', $grant);
+                    } else {
+                        $grantsSelect->where($quotedGrant . ' LIKE ?', $grant);
+                    }
+                    ++$iteration;
+                } else {
+                    $grantsSelect->orWhere($quotedGrant . ' LIKE ?', $grant);
+                }
             }
+
+            // admin grant includes all other grants
+            if (! in_array(Tinebase_Model_Grants::GRANT_ADMIN, $grants)) {
+                $grantsSelect->orWhere($quotedGrant . ' LIKE ?', Tinebase_Model_Grants::GRANT_ADMIN);
+            }
+
             $grantsSelect->appendWhere(Zend_Db_Select::SQL_AND);
         }
     }
@@ -767,10 +782,11 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
      * @param   string|Tinebase_Model_Application   $recordClass
      * @param   array|string                        $_grant
      * @param   bool                                $_ignoreACL
+     * @param   bool                                $_andGrants
      * @return  Tinebase_Record_RecordSet set of Tinebase_Model_Container
      * @throws  Tinebase_Exception_NotFound
      */
-    public function getSharedContainer($_accountId, $recordClass, $_grant, $_ignoreACL = FALSE)
+    public function getSharedContainer($_accountId, $recordClass, $_grant, $_ignoreACL = FALSE, $_andGrants = FALSE)
     {
         // legacy handling
         $meta = $this->_resolveRecordClassArgument($recordClass);
@@ -782,7 +798,8 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
             $accountId .
             $application->getId() .
             implode('', (array)$grant) .
-            (int)$_ignoreACL
+            (int)$_ignoreACL .
+            (int)$_andGrants
         );
         
         try {
@@ -804,7 +821,7 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
             
             ->order('container.name');
         
-        $this->addGrantsSql($select, $accountId, $grant);
+        $this->addGrantsSql($select, $accountId, $grant, 'container_acl', $_andGrants, __CLASS__ . '::addGrantsSqlCallback');
         
         $stmt = $this->_db->query('/*' . __FUNCTION__ . '*/' . $select);
         
@@ -826,19 +843,38 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
      * @param   string|Tinebase_Model_Application   $recordClass
      * @param   array|string                        $_grant
      * @param   bool                                $_ignoreACL
+     * @param   bool                                $_andGrants
      * @return  Tinebase_Record_RecordSet set of Tinebase_Model_User
      */
-    public function getOtherUsers($_accountId, $recordClass, $_grant, $_ignoreACL = FALSE)
+    public function getOtherUsers($_accountId, $recordClass, $_grant, $_ignoreACL = FALSE, $_andGrants = FALSE)
     {
         $meta = $this->_resolveRecordClassArgument($recordClass);
-        $userIds = $this->_getOtherAccountIds($_accountId, $meta['appName'], $_grant, $_ignoreACL);
+        $userIds = $this->_getOtherAccountIds($_accountId, $meta['appName'], $_grant, $_ignoreACL, $_andGrants);
         
         $users = Tinebase_User::getInstance()->getMultiple($userIds);
         $users->sort('accountDisplayName');
         
         return $users;
     }
-    
+
+    /**
+     * appends container_acl sql
+     *
+     * @param  Zend_Db_Select    $_select
+     * @param  integer           $iteration
+     * @return string table identifier to work on
+     */
+    public static function addGrantsSqlCallback($_select, $iteration)
+    {
+        $db = $_select->getAdapter();
+        $_select->join(array(
+            /* table  */ 'container_acl' . $iteration => SQL_TABLE_PREFIX . 'container_acl'),
+            /* on     */ $db->quoteIdentifier('container_acl' . $iteration . '.container_id') . ' = ' . $db->quoteIdentifier('container.id'),
+            array()
+        );
+        return 'container_acl' . $iteration;
+    }
+
     /**
      * return account ids of accounts which made personal container accessible to given account
      *
@@ -846,15 +882,16 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
      * @param   string|Tinebase_Model_Application   $_application
      * @param   array|string                        $_grant
      * @param   bool                                $_ignoreACL
+     * @param   bool                                $_andGrants
      * @return  array of array of containerData
      */
-    protected function _getOtherAccountIds($_accountId, $_application, $_grant, $_ignoreACL = FALSE)
+    protected function _getOtherAccountIds($_accountId, $_application, $_grant, $_ignoreACL = FALSE, $_andGrants = FALSE)
     {
         $accountId   = Tinebase_Model_User::convertUserIdToInt($_accountId);
         $application = Tinebase_Application::getInstance()->getApplicationByName($_application);
         $grant       = $_ignoreACL ? '*' : $_grant;
 
-        $classCacheId = Tinebase_Helper::convertCacheId($accountId . $application->getId() . implode('', (array)$grant) .(int)$_ignoreACL);
+        $classCacheId = Tinebase_Helper::convertCacheId($accountId . $application->getId() . implode('', (array)$grant) . (int)$_ignoreACL . (int)$_andGrants);
         try {
             return $this->loadFromClassCache(__FUNCTION__, $classCacheId);
         } catch (Tinebase_Exception_NotFound $tenf) {
@@ -873,9 +910,9 @@ class Tinebase_Container extends Tinebase_Backend_Sql_Abstract
             ->where("{$this->_db->quoteIdentifier('container.application_id')} = ?", $application->getId())
             ->where("{$this->_db->quoteIdentifier('container.type')} = ?", Tinebase_Model_Container::TYPE_PERSONAL)
             ->where("{$this->_db->quoteIdentifier('container.is_deleted')} = ?", 0, Zend_Db::INT_TYPE);
-            
-        $this->addGrantsSql($select, $accountId, $grant);
-        
+
+        $this->addGrantsSql($select, $accountId, $grant, 'container_acl', $_andGrants, __CLASS__ . '::addGrantsSqlCallback');
+
         $stmt = $this->_db->query('/*' . __FUNCTION__ . '*/' . $select);
         $containerIds = $stmt->fetchAll(Zend_Db::FETCH_COLUMN);