CRM-14676 - need to escape names before inserting into prev_next_cache
[civicrm-core.git] / CRM / Contact / Selector.php
index c8776ef9f181a65bd4f758590e51aa66320dc9b5..ad3f6f119b2216522acfc11037052d98895d2103 100644 (file)
@@ -326,6 +326,19 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
    */
   function &getColumnHeaders($action = NULL, $output = NULL) {
     $headers = NULL;
+
+    // unset return property elements that we don't care
+    if (!empty($this->_returnProperties)) {
+      $doNotCareElements = array(
+        'contact_type',
+        'contact_sub_type',
+        'sort_name',
+      );
+      foreach ( $doNotCareElements as $value) {
+        unset($this->_returnProperties[$value]);
+      }
+    }
+
     if ($output == CRM_Core_Selector_Controller::EXPORT) {
       $csvHeaders = array(ts('Contact Id'), ts('Contact Type'));
       foreach ($this->getColHeads($action, $output) as $column) {
@@ -428,10 +441,6 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
       $properties = self::makeProperties($this->_returnProperties);
 
       foreach ($properties as $prop) {
-        if ($prop == 'contact_type' || $prop == 'contact_sub_type' || $prop == 'sort_name') {
-          continue;
-        }
-
         if (strpos($prop, '-')) {
           list($loc, $fld, $phoneType) = CRM_Utils_System::explode('-', $prop, 3);
           $title = $this->_query->_fields[$fld]['title'];
@@ -442,7 +451,8 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
         }
         elseif (isset($this->_query->_fields[$prop]) && isset($this->_query->_fields[$prop]['title'])) {
           $title = $this->_query->_fields[$prop]['title'];
-        } else {
+        }
+        else {
           $title = '';
         }
 
@@ -640,9 +650,6 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
           $greeting = $property . '_display';
           $row[$property] = $result->$greeting;
         }
-        elseif ($property == 'state_province') {
-          $row[$property] = $result->state_province_name;
-        }
         elseif (isset($pseudoconstants[$property])) {
           $row[$property] = CRM_Utils_Array::value(
             $result->{$pseudoconstants[$property]['dbName']},
@@ -886,19 +893,17 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
    * @param int $end
    */
   function fillupPrevNextCache($sort, $cacheKey, $start = 0, $end = 500) {
-
+    $coreSearch = TRUE;
     // For custom searches, use the contactIDs method
     if (is_a($this, 'CRM_Contact_Selector_Custom')) {
       $sql = $this->_search->contactIDs($start, $end, $sort, TRUE);
       $replaceSQL = "SELECT contact_a.id as contact_id";
+      $coreSearch = FALSE;
     }
     // For core searches use the searchQuery method
     else {
-      $sql = $this->_query->searchQuery(
-        $start, $end, $sort,
-        FALSE, FALSE,
-        FALSE, TRUE, TRUE, NULL
-      );
+      $sql = $this->_query->searchQuery($start, $end, $sort, FALSE, $this->_query->_includeContactIds,
+        FALSE, TRUE, TRUE);
       $replaceSQL = "SELECT contact_a.id as id";
     }
 
@@ -918,22 +923,59 @@ SELECT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.dis
 
     $sql = str_replace($replaceSQL, $insertSQL, $sql);
 
-
     CRM_Core_Error::ignoreException();
     $result = CRM_Core_DAO::executeQuery($sql);
     CRM_Core_Error::setCallback();
 
     if (is_a($result, 'DB_Error')) {
-      // oops the above query failed, so lets just ignore it
-      // and return
-      // we print a sorry cant figure it out on view page
-      return;
+      // check if we get error during core search
+      if ($coreSearch) {
+        // in the case of error, try rebuilding cache using full sql which is used for search selector display
+        // this fixes the bugs reported in CRM-13996 & CRM-14438
+        $this->rebuildPreNextCache($start, $end, $sort, $cacheKey);
+      }
+      else {
+        // return if above query fails
+        return;
+      }
     }
 
     // also record an entry in the cache key table, so we can delete it periodically
     CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey);
   }
 
+  /**
+   * This function is called to rebuild prev next cache using full sql in case of core search ( excluding custom search)
+   *
+   * @param int $start start for limit clause
+   * @param int $end end for limit clause
+   * @param $object $sort sort object
+   * @param string $cacheKey cache key
+   *
+   * @return void
+   */
+  function rebuildPreNextCache($start, $end, $sort, $cacheKey) {
+    // generate full SQL
+    $sql = $this->_query->searchQuery($start, $end, $sort, FALSE, $this->_query->_includeContactIds,
+      FALSE, FALSE, TRUE);
+
+    $dao = CRM_Core_DAO::executeQuery($sql);
+
+    // build insert query, note that currently we build cache for 500 contact records at a time, hence below approach
+    $insertValues = array();
+    while($dao->fetch()) {
+      $insertValues[] = "('civicrm_contact', {$dao->contact_id}, {$dao->contact_id}, '{$cacheKey}', '" . CRM_Core_DAO::escapeString($dao->sort_name) . "')";
+    }
+
+    //update pre/next cache using single insert query
+    if (!empty($insertValues)) {
+      $sql = 'INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data ) VALUES
+'.implode(',', $insertValues);
+
+      $result = CRM_Core_DAO::executeQuery($sql);
+    }
+  }
+
   /**
    * Given the current formValues, gets the query in local
    * language