Add additional of customFieldTableJoins to be calculated for filters separately to...
authoreileen <emcnaughton@wikimedia.org>
Fri, 22 Jan 2016 02:10:38 +0000 (15:10 +1300)
committereileen <emcnaughton@wikimedia.org>
Fri, 22 Jan 2016 02:35:39 +0000 (15:35 +1300)
This means that if the report runs 2 queries, one to get the filtered list of subjects and a second to render the appropriate fields for them the first query (likely to be bigger) can avoid joining in tables that are only used for rendering results

Change-Id: Iee0078054abe8b5e63435e66f9215fc2fd9cd62f

Change-Id: Ic4e9ed36cf1a186aeeb1c44d59661e8971612022

CRM/Report/Form.php

index 9bf3f3044549cbeb0822ef720483f091cddef01b..8e2327a780c21fc483ce4fe75b40eb5437528112 100644 (file)
@@ -296,12 +296,21 @@ class CRM_Report_Form extends CRM_Core_Form {
   protected $_aclWhere = NULL;
 
   /**
-   * Array of DAO tables having columns included in SELECT or ORDER BY clause
+   * Array of DAO tables having columns included in SELECT or ORDER BY clause.
+   *
+   * Where has also been added to this although perhaps the 'includes both' array should have a different name.
    *
    * @var array
    */
   protected $_selectedTables;
 
+  /**
+   * Array of DAO tables having columns included in WHERE or HAVING clause
+   *
+   * @var array
+   */
+  protected $filteredTables;
+
   /**
    * Output mode e.g 'print', 'csv', 'pdf'.
    *
@@ -3628,8 +3637,11 @@ ORDER BY cg.weight, cf.weight";
 
   /**
    * Build custom data from clause.
+   *
+   * @param bool $joinsForFiltersOnly
+   *   Only include joins to support filters. This would be used if creating a table of contacts to include first.
    */
-  public function customDataFrom() {
+  public function customDataFrom($joinsForFiltersOnly = FALSE) {
     if (empty($this->_customGroupExtends)) {
       return;
     }
@@ -3639,9 +3651,8 @@ ORDER BY cg.weight, cf.weight";
     foreach ($this->_columns as $table => $prop) {
       if (in_array($table, $customTables)) {
         $extendsTable = $mapper[$prop['extends']];
-
-        // check field is in params
-        if (!$this->isFieldSelected($prop)) {
+        // Check field is required for rendering the report.
+        if ((!$this->isFieldSelected($prop)) || ($joinsForFiltersOnly && !$this->isFieldFiltered($prop))) {
           continue;
         }
         $baseJoin = CRM_Utils_Array::value($prop['extends'], $this->_customGroupExtendsJoin, "{$this->_aliases[$extendsTable]}.id");
@@ -3716,7 +3727,18 @@ LEFT JOIN civicrm_contact {$field['alias']} ON {$field['alias']}.id = {$this->_a
         }
       }
     }
+    return $this->isFieldFiltered($prop);
+
+  }
 
+  /**
+   * Check if the field is used as a filter.
+   *
+   * @param string $prop
+   *
+   * @return bool
+   */
+  protected function isFieldFiltered($prop) {
     if (!empty($prop['filters']) && $this->_customGroupFilters) {
       foreach ($prop['filters'] as $fieldAlias => $val) {
         foreach (array(
@@ -3802,6 +3824,22 @@ LEFT JOIN civicrm_contact {$field['alias']} ON {$field['alias']}.id = {$this->_a
     return in_array($tableName, $this->selectedTables());
   }
 
+  /**
+   * Check if table name has columns in WHERE or HAVING clause.
+   *
+   * @param string $tableName
+   *   Name of table (index of $this->_columns array).
+   *
+   * @return bool
+   */
+  public function isTableFiltered($tableName) {
+    // Cause the array to be generated if not previously done.
+    if (!$this->_selectedTables && !$this->filteredTables) {
+      $this->selectedTables();
+    }
+    return in_array($tableName, $this->filteredTables);
+  }
+
   /**
    * Fetch array of DAO tables having columns included in SELECT or ORDER BY clause.
    *
@@ -3849,6 +3887,7 @@ LEFT JOIN civicrm_contact {$field['alias']} ON {$field['alias']}.id = {$this->_a
               'nnll'
             ) {
               $this->_selectedTables[] = $tableName;
+              $this->filteredTables[] = $tableName;
               break;
             }
           }