CRM-19557 Fix ACL caching function to not use inefficient query for view my contact
authoreileenmcnaugton <eileen@fuzion.co.nz>
Mon, 24 Oct 2016 08:50:26 +0000 (21:50 +1300)
committereileenmcnaugton <eileen@fuzion.co.nz>
Mon, 24 Oct 2016 09:37:34 +0000 (22:37 +1300)
Conflicts:
CRM/Contact/BAO/Contact/Permission.php

CRM/ACL/API.php
CRM/Contact/BAO/Contact/Permission.php

index 113bcce0e9250eb7871bc196f68d6b9756eb3953..27ce2b1561a7ae485780685d3f1d0f569e45aa3f 100644 (file)
@@ -84,6 +84,10 @@ class CRM_ACL_API {
    * @param bool $skipDeleteClause
    *   Don't add delete clause if this is true,.
    *   this means it is handled by generating query
+   * @param bool $skipOwnContactClause
+   *   Do not add 'OR contact_id = $userID' to the where clause.
+   *   This is a hideously inefficient query and should be avoided
+   *   wherever possible.
    *
    * @return string
    *   the group where clause for this user
@@ -94,7 +98,8 @@ class CRM_ACL_API {
     &$whereTables,
     $contactID = NULL,
     $onlyDeleted = FALSE,
-    $skipDeleteClause = FALSE
+    $skipDeleteClause = FALSE,
+    $skipOwnContactClause = FALSE
   ) {
     // the default value which is valid for the final AND
     $deleteClause = ' ( 1 ) ';
@@ -131,9 +136,9 @@ class CRM_ACL_API {
       )
     );
 
-    // Add permission on self
-    if ($contactID && (CRM_Core_Permission::check('edit my contact') ||
-      $type == self::VIEW && CRM_Core_Permission::check('view my contact'))
+    // Add permission on self if we really hate our server or have hardly any contacts.
+    if (!$skipOwnContactClause && $contactID && (CRM_Core_Permission::check('edit my contact') ||
+        $type == self::VIEW && CRM_Core_Permission::check('view my contact'))
     ) {
       $where = "(contact_a.id = $contactID OR ($where))";
     }
index 88767deb9a8d4620341b13dc5fe30d4f56b85b06..ceb765cdad9d1aecb3e959788e63f2664e2497ad 100644 (file)
@@ -103,7 +103,7 @@ class CRM_Contact_BAO_Contact_Permission {
 SELECT contact_id
  FROM civicrm_acl_contact_cache
  {$LEFT_JOIN_DELETED}
-WHERE contact_id IN ({$contact_id_list}) 
+WHERE contact_id IN ({$contact_id_list})
   AND user_id = {$contactID}
   AND operation = '{$operation}'
   {$AND_CAN_ACCESS_DELETED}";
@@ -211,6 +211,7 @@ WHERE contact_a.id = %1 AND $permission
       $operationClause = " operation = 'Edit' ";
       $operation = 'Edit';
     }
+    $queryParams = array(1 => array($userID, 'Integer'));
 
     if (!$force) {
       // skip if already calculated
@@ -225,8 +226,7 @@ FROM   civicrm_acl_contact_cache
 WHERE  user_id = %1
 AND    $operationClause
 ";
-      $params = array(1 => array($userID, 'Integer'));
-      $count = CRM_Core_DAO::singleValueQuery($sql, $params);
+      $count = CRM_Core_DAO::singleValueQuery($sql, $queryParams);
       if ($count > 0) {
         $_processed[$type][$userID] = 1;
         return;
@@ -236,7 +236,7 @@ AND    $operationClause
     $tables = array();
     $whereTables = array();
 
-    $permission = CRM_ACL_API::whereClause($type, $tables, $whereTables, $userID);
+    $permission = CRM_ACL_API::whereClause($type, $tables, $whereTables, $userID, FALSE, FALSE, TRUE);
 
     $from = CRM_Contact_BAO_Query::fromClause($whereTables);
     CRM_Core_DAO::executeQuery("
@@ -247,6 +247,16 @@ SELECT DISTINCT $userID as user_id, contact_a.id as contact_id, '{$operation}' a
 WHERE    $permission
 AND ac.user_id IS NULL
 ");
+
+    // Add in a row for the logged in contact. Do not try to combine with the above query or an ugly OR will appear in
+    // the permission clause.
+    if (CRM_Core_Permission::check('edit my contact') ||
+      ($type == CRM_Core_Permission::VIEW && CRM_Core_Permission::check('view my contact'))) {
+      if (!CRM_Core_DAO::executeQuery("
+        SELECT count(*) FROM civicrm_acl_contact_cache WHERE user_id = %1 AND contact_id = %1 AND operation = '{$operation}'", $queryParams)) {
+        CRM_Core_DAO::executeQuery("INSERT INTO civicrm_acl_contact_cache ( user_id, contact_id, operation ) VALUES(%1, %1, '{$operation}')");
+      }
+    }
     $_processed[$type][$userID] = 1;
   }
 
@@ -353,7 +363,7 @@ AND ac.user_id IS NULL
 
       $queries[] = "
 SELECT civicrm_relationship.{$contact_id_column} AS contact_id
-  FROM civicrm_relationship 
+  FROM civicrm_relationship
   {$LEFT_JOIN_DELETED}
  WHERE civicrm_relationship.{$user_id_column} = {$contactID}
    AND civicrm_relationship.{$contact_id_column} IN ({$contact_id_list})