Merge pull request #14326 from civicrm/5.14
[civicrm-core.git] / CRM / Core / Form / Search.php
index 5d4ed98a0a3a66c040036f8bef5b696a6210032f..ede46d09d6fd7f98bb6fd25c97f5ee306a6ad0f4 100644 (file)
@@ -61,7 +61,7 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
   /**
    * Have we already done this search
    *
-   * @var boolean
+   * @var bool
    */
   protected $_done;
 
@@ -77,7 +77,7 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    *
    * @var array
    */
-  protected $_taskList = array();
+  protected $_taskList = [];
 
   /**
    * Declare entity reference fields as they will need to be converted.
@@ -87,7 +87,7 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    *
    * @var array
    */
-  protected $entityReferenceFields = array();
+  protected $entityReferenceFields = [];
 
   /**
    * Builds the list of tasks or actions that a searcher can perform on a result set.
@@ -130,13 +130,13 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
       ->addScriptFile('civicrm', 'js/crm.searchForm.js', 1, 'html-header')
       ->addStyleFile('civicrm', 'css/searchForm.css', 1, 'html-header');
 
-    $this->addButtons(array(
-      array(
+    $this->addButtons([
+      [
         'type' => 'refresh',
         'name' => ts('Search'),
         'isDefault' => TRUE,
-      ),
-    ));
+      ],
+    ]);
 
     $this->addClass('crm-search-form');
 
@@ -151,12 +151,12 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    * than existing ad hoc handling.
    */
   public function addFormFieldsFromMetadata() {
+    $this->addFormRule(['CRM_Core_Form_Search', 'formRule'], $this);
     $this->_action = CRM_Core_Action::ADVANCED;
     foreach ($this->getSearchFieldMetadata() as $entity => $fields) {
       foreach ($fields as $fieldName => $fieldSpec) {
-        if ($fieldSpec['type'] === CRM_Utils_Type::T_DATE) {
-          // Assuming time is false for now as we are not checking for date-time fields as yet.
-          $this->addDatePickerRange($fieldName, $fieldSpec['title'], FALSE);
+        if ($fieldSpec['type'] === CRM_Utils_Type::T_DATE || $fieldSpec['type'] === (CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME)) {
+          $this->addDatePickerRange($fieldName, $fieldSpec['title'], ($fieldSpec['type'] === (CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME)));
         }
         else {
           $this->addField($fieldName, ['entity' => $entity]);
@@ -165,6 +165,38 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
     }
   }
 
+  /**
+   * Global validation rules for the form.
+   *
+   * @param array $fields
+   *   Posted values of the form.
+   * @param array $files
+   * @param object $form
+   *
+   * @return array
+   *   list of errors to be posted back to the form
+   */
+  public static function formRule($fields, $files, $form) {
+    $errors = [];
+    if (!is_a($form, 'CRM_Core_Form_Search')) {
+      // So this gets hit with a form object when doing an activity date search from
+      // advanced search, but a NULL object when doing a pledge search.
+      return $errors;
+    }
+    foreach ($form->getSearchFieldMetadata() as $entity => $spec) {
+      foreach ($spec as $fieldName => $fieldSpec) {
+        if ($fieldSpec['type'] === CRM_Utils_Type::T_DATE || $fieldSpec['type'] === (CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME)) {
+          if (isset($fields[$fieldName . '_high']) && isset($fields[$fieldName . '_low']) && empty($fields[$fieldName . '_relative'])) {
+            if (strtotime($fields[$fieldName . '_low']) > strtotime($fields[$fieldName . '_high'])) {
+              $errors[$fieldName . '_low'] = ts('%1: Please check that your date range is in correct chronological order.', [1 => $fieldSpec['title']]);
+            }
+          }
+        }
+      }
+    }
+    return $errors;
+  }
+
   /**
    * Get the validation rule to apply to a function.
    *
@@ -184,6 +216,10 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
       case CRM_Utils_Type::T_INT:
         return 'CommaSeparatedIntegers';
 
+      case CRM_Utils_Type::T_DATE:
+      case CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME:
+        return 'Timestamp';
+
       default:
         return 'Alphanumeric';
     }
@@ -204,6 +240,15 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
         if ($value !== FALSE) {
           $defaults[$fieldSpec['name']] = $value;
         }
+        if ($fieldSpec['type'] === CRM_Utils_Type::T_DATE || ($fieldSpec['type'] === CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME)) {
+          $low = CRM_Utils_Request::retrieveValue($fieldSpec['name'] . '_low', 'Timestamp', FALSE, NULL, 'GET');
+          $high = CRM_Utils_Request::retrieveValue($fieldSpec['name'] . '_high', 'Timestamp', FALSE, NULL, 'GET');
+          if ($low !== FALSE || $high !== FALSE) {
+            $defaults[$fieldSpec['name'] . '_relative'] = 0;
+            $defaults[$fieldSpec['name'] . '_low'] = $low ? date('Y-m-d H:i:s', strtotime($low)) : NULL;
+            $defaults[$fieldSpec['name'] . '_high'] = $high ? date('Y-m-d H:i:s', strtotime($high)) : NULL;
+          }
+        }
       }
     }
     return $defaults;
@@ -215,11 +260,11 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    * @param array $rows
    */
   public function addRowSelectors($rows) {
-    $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('class' => 'select-rows'));
+    $this->addElement('checkbox', 'toggleSelect', NULL, NULL, ['class' => 'select-rows']);
     if (!empty($rows)) {
       foreach ($rows as $row) {
         if (CRM_Utils_Array::value('checkbox', $row)) {
-          $this->addElement('checkbox', $row['checkbox'], NULL, NULL, array('class' => 'select-row'));
+          $this->addElement('checkbox', $row['checkbox'], NULL, NULL, ['class' => 'select-row']);
         }
       }
     }
@@ -231,9 +276,9 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    * @param array $tasks
    */
   public function addTaskMenu($tasks) {
-    $taskMetaData = array();
+    $taskMetaData = [];
     foreach ($tasks as $key => $task) {
-      $taskMetaData[$key] = array('title' => $task);
+      $taskMetaData[$key] = ['title' => $task];
     }
     parent::addTaskMenu($taskMetaData);
   }
@@ -251,7 +296,7 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
     $this->addElement(
       'text',
       'sort_name',
-      civicrm_api3('setting', 'getvalue', array('name' => 'includeEmailInName', 'group' => 'Search Preferences')) ? $this->getSortNameLabelWithEmail() : $this->getSortNameLabelWithOutEmail(),
+      civicrm_api3('setting', 'getvalue', ['name' => 'includeEmailInName', 'group' => 'Search Preferences']) ? $this->getSortNameLabelWithEmail() : $this->getSortNameLabelWithOutEmail(),
       CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')
     );
   }
@@ -297,25 +342,25 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
     $this->_group = CRM_Core_PseudoConstant::nestedGroup();
     if ($this->_group) {
       $this->add('select', 'group', $this->getGroupLabel(), $this->_group, FALSE,
-        array(
+        [
           'id' => 'group',
           'multiple' => 'multiple',
           'class' => 'crm-select2',
-        )
+        ]
       );
     }
 
     $contactTags = CRM_Core_BAO_Tag::getTags();
     if ($contactTags) {
       $this->add('select', 'contact_tags', $this->getTagLabel(), $contactTags, FALSE,
-        array(
+        [
           'id' => 'contact_tags',
           'multiple' => 'multiple',
           'class' => 'crm-select2',
-        )
+        ]
       );
     }
-    $this->addField('contact_type', array('entity' => 'Contact'));
+    $this->addField('contact_type', ['entity' => 'Contact']);
 
     if (CRM_Core_Permission::check('access deleted contacts') && Civi::settings()->get('contact_undelete')) {
       $this->addElement('checkbox', 'deleted_contacts', ts('Search in Trash') . '<br />' . ts('(deleted contacts)'));