Merge pull request #12072 from civicrm/5.1
[civicrm-core.git] / CRM / Contact / Form / Search / Custom / Proximity.php
index 8375adee013f87b3c592de469543ab6fd317d3b6..e5d5f339f0050747cb1b11b55383617161bc7571 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.7                                                |
+ | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2017                                |
+ | Copyright CiviCRM LLC (c) 2004-2018                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
  */
 
 /**
+ *
+ * This search now functions as a subset of advanced search since at some point it
+ * was added to advanced search.
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2017
+ * @copyright CiviCRM LLC (c) 2004-2018
  */
 class CRM_Contact_Form_Search_Custom_Proximity extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
 
@@ -55,24 +58,7 @@ class CRM_Contact_Form_Search_Custom_Proximity extends CRM_Contact_Form_Search_C
 
     if (!empty($this->_formValues)) {
       // add the country and state
-      if (!empty($this->_formValues['country_id'])) {
-        $this->_formValues['country'] = CRM_Core_PseudoConstant::country($this->_formValues['country_id']);
-      }
-
-      if (!empty($this->_formValues['state_province_id'])) {
-        $this->_formValues['state_province'] = CRM_Core_PseudoConstant::stateProvince($this->_formValues['state_province_id']);
-      }
-
-      // use the address to get the latitude and longitude
-      CRM_Utils_Geocode_Google::format($this->_formValues);
-
-      if (!is_numeric(CRM_Utils_Array::value('geo_code_1', $this->_formValues)) ||
-        !is_numeric(CRM_Utils_Array::value('geo_code_2', $this->_formValues)) ||
-        !isset($this->_formValues['distance'])
-      ) {
-        CRM_Core_Error::fatal(ts('Could not geocode input'));
-      }
-
+      self::addGeocodingData($this->_formValues);
       $this->_latitude = $this->_formValues['geo_code_1'];
       $this->_longitude = $this->_formValues['geo_code_2'];
 
@@ -98,6 +84,15 @@ class CRM_Contact_Form_Search_Custom_Proximity extends CRM_Contact_Form_Search_C
     );
   }
 
+  /**
+   * Get the query object for this selector.
+   *
+   * @return CRM_Contact_BAO_Query
+   */
+  public function getQueryObj() {
+    return $this->_query;
+  }
+
   /**
    * @param CRM_Core_Form $form
    */
@@ -135,6 +130,9 @@ class CRM_Contact_Form_Search_Custom_Proximity extends CRM_Contact_Form_Search_C
     $country = array('' => ts('- select -')) + CRM_Core_PseudoConstant::country();
     $form->add('select', 'country_id', ts('Country'), $country, TRUE, array('class' => 'crm-select2'));
 
+    $form->add('text', 'geo_code_1', ts('Latitude'));
+    $form->add('text', 'geo_code_2', ts('Longitude'));
+
     $group = array('' => ts('- any group -')) + CRM_Core_PseudoConstant::nestedGroup();
     $form->addElement('select', 'group', ts('Group'), $group, array('class' => 'crm-select2 huge'));
 
@@ -176,20 +174,7 @@ class CRM_Contact_Form_Search_Custom_Proximity extends CRM_Contact_Form_Search_C
     $offset = 0, $rowcount = 0, $sort = NULL,
     $includeContactIDs = FALSE, $justIDs = FALSE
   ) {
-    if ($justIDs) {
-      $selectClause = "contact_a.id as contact_id";
-    }
-    else {
-      $selectClause = "
-contact_a.id           as contact_id    ,
-contact_a.sort_name    as sort_name     ,
-address.street_address as street_address,
-address.city           as city          ,
-address.postal_code    as postal_code   ,
-state_province.name    as state_province,
-country.name           as country
-";
-    }
+    $selectClause = $justIDs ? "contact_a.id as contact_id" : NULL;
 
     return $this->sql($selectClause,
       $offset, $rowcount, $sort,
@@ -198,66 +183,79 @@ country.name           as country
   }
 
   /**
+   * Override sql() function to use the Query object rather than generating on the form.
+   *
+   * @param string $selectClause
+   * @param int $offset
+   * @param int $rowcount
+   * @param null $sort
+   * @param bool $includeContactIDs
+   * @param null $groupBy
+   *
    * @return string
    */
-  public function from() {
-    $this->buildACLClause('contact_a');
-    $f = "
-FROM      civicrm_contact contact_a
-LEFT JOIN civicrm_address address ON ( address.contact_id       = contact_a.id AND
-                                       address.is_primary       = 1 )
-LEFT JOIN civicrm_state_province state_province ON state_province.id = address.state_province_id
-LEFT JOIN civicrm_country country               ON country.id        = address.country_id {$this->_aclFrom}
-";
-
-    // This prevents duplicate rows when contacts have more than one tag any you select "any tag"
-    if ($this->_tag) {
-      $f .= "
-LEFT JOIN civicrm_entity_tag t ON (t.entity_table='civicrm_contact' AND contact_a.id = t.entity_id)
-";
+  public function sql(
+    $selectClause,
+    $offset = 0,
+    $rowcount = 0,
+    $sort = NULL,
+    $includeContactIDs = FALSE,
+    $groupBy = NULL
+  ) {
+
+    $isCountOnly = FALSE;
+    if ($selectClause === 'count(distinct contact_a.id) as total') {
+      $isCountOnly = TRUE;
     }
-    if ($this->_group) {
-      $f .= "
-LEFT JOIN civicrm_group_contact cgc ON ( cgc.contact_id = contact_a.id AND cgc.status = 'Added')
-";
+
+    $searchParams = [
+      ['prox_distance_unit', '=', $this->_formValues['prox_distance_unit'], 0, 0],
+      ['prox_distance', '=', $this->_formValues['distance'], 0, 0],
+      ['prox_geo_code_1', '=', $this->_formValues['geo_code_1'], 0, 0],
+      ['prox_geo_code_2', '=', $this->_formValues['geo_code_2'], 0, 0],
+    ];
+    if (!empty($this->_formValues['group'])) {
+      $searchParams[] = ['group', '=', ['IN', (array) $this->_formValues['group']][1], 0, 0];
+    }
+    if (!empty($this->_formValues['tag'])) {
+      $searchParams[] = ['contact_tags', '=', ['IN', (array) $this->_formValues['tag']][1], 0, 0];
     }
 
-    return $f;
+    $display = array_fill_keys(['city', 'state_province', 'country', 'postal_code', 'street_address', 'display_name', 'sort_name'], 1);
+    if ($selectClause === 'contact_a.id as contact_id') {
+      // Not sure when this would happen but calling all with 'justIDs' gets us here.
+      $display = ['contact_id' => 1];
+    }
+
+    $this->_query = new CRM_Contact_BAO_Query($searchParams, $display);
+    return $this->_query->searchQuery(
+      $offset,
+      $rowcount,
+      $sort,
+      $isCountOnly,
+      $includeContactIDs,
+      FALSE,
+      $isCountOnly,
+      $returnQuery = TRUE
+    );
+
   }
 
+  /**
+   * @return string
+   */
+  public function from() {
+    //unused
+    return '';
+  }
   /**
    * @param bool $includeContactIDs
    *
    * @return string
    */
   public function where($includeContactIDs = FALSE) {
-    $params = array();
-    $clause = array();
-
-    $where = CRM_Contact_BAO_ProximityQuery::where($this->_latitude,
-      $this->_longitude,
-      $this->_distance,
-      'address'
-    );
-
-    if ($this->_tag) {
-      $where .= "
-AND t.tag_id = {$this->_tag}
-";
-    }
-    if ($this->_group) {
-      $where .= "
-AND cgc.group_id = {$this->_group}
- ";
-    }
-
-    $where .= " AND contact_a.is_deleted != 1 ";
-
-    if ($this->_aclWhere) {
-      $where .= " AND {$this->_aclWhere} ";
-    }
-
-    return $this->whereClause($where, $params);
+    //unused
+    return '';
   }
 
   /**
@@ -314,10 +312,42 @@ AND cgc.group_id = {$this->_group}
   }
 
   /**
-   * @param string $tableAlias
+   * Validate form input.
+   *
+   * @param array $fields
+   * @param array $files
+   * @param CRM_Core_Form $self
+   *
+   * @return array
+   *   Input errors from the form.
+   */
+  public function formRule($fields, $files, $self) {
+    $this->addGeocodingData($fields);
+
+    if (!is_numeric(CRM_Utils_Array::value('geo_code_1', $fields)) ||
+      !is_numeric(CRM_Utils_Array::value('geo_code_2', $fields)) ||
+      !isset($fields['distance'])
+    ) {
+      $errorMessage = ts('Could not determine co-ordinates for provided data');
+      return array_fill_keys(['street_address', 'city', 'postal_code', 'country_id', 'state_province_id'], $errorMessage);
+    }
+    return [];
+  }
+
+  /**
+   * Add the geocoding data to the fields supplied.
+   *
+   * @param array $fields
    */
-  public function buildACLClause($tableAlias = 'contact') {
-    list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause($tableAlias);
+  protected function addGeocodingData(&$fields) {
+    if (!empty($fields['country_id'])) {
+      $fields['country'] = CRM_Core_PseudoConstant::country($fields['country_id']);
+    }
+
+    if (!empty($fields['state_province_id'])) {
+      $fields['state_province'] = CRM_Core_PseudoConstant::stateProvince($fields['state_province_id']);
+    }
+    CRM_Core_BAO_Address::addGeocoderData($fields);
   }
 
 }