From 27cedb985f9e7ba86bd9069eacef9e715d6bfb21 Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 2 Mar 2019 18:48:47 +1300 Subject: [PATCH 1/6] Convert activity_date_time field to datepicker and add support for url input This converts the form to being a metadata defined field & a date-picker field as well as adding standardised url support for input. The input format is activity_date_time_high=20100101 I stripped out the complex and probably broken based on feedback & not used in core existing hard-coded url support. Note that there are some outstanding items 1) the upgrade script item needs to be added - this includes dealing with renaming of the field since I made it more consistent 2) I stripped out the check to ensure the high date is greater than the low date - if we still want this we should re-add as a generic thing. My guess is it's a bit optional --- CRM/Activity/BAO/Query.php | 31 +++---------------- CRM/Activity/Form/Search.php | 25 --------------- CRM/Contact/BAO/Query.php | 2 ++ CRM/Core/Form.php | 6 ++-- CRM/Core/Form/Search.php | 18 +++++++++-- templates/CRM/Activity/Form/Search/Common.tpl | 7 ++--- 6 files changed, 28 insertions(+), 61 deletions(-) diff --git a/CRM/Activity/BAO/Query.php b/CRM/Activity/BAO/Query.php index 1bba431fa21e..3477ffef6ac6 100644 --- a/CRM/Activity/BAO/Query.php +++ b/CRM/Activity/BAO/Query.php @@ -288,8 +288,10 @@ public static function whereClauseSingle(&$values, &$query) { case 'activity_date': case 'activity_date_low': case 'activity_date_high': + case 'activity_date_time_low': + case 'activity_date_time_high': $query->dateQueryBuilder($values, - 'civicrm_activity', 'activity_date', 'activity_date_time', ts('Activity Date') + 'civicrm_activity', str_replace(['_high', '_low'], '', $name), 'activity_date_time', ts('Activity Date') ); break; @@ -440,7 +442,7 @@ public static function from($name, $mode, $side) { * rather than a static function. */ public static function getSearchFieldMetadata() { - $fields = ['activity_type_id']; + $fields = ['activity_type_id', 'activity_date_time']; $metadata = civicrm_api3('Activity', 'getfields', [])['values']; return array_intersect_key($metadata, array_flip($fields)); } @@ -454,10 +456,6 @@ public static function buildSearchForm(&$form) { $form->addSearchFieldMetadata(['Activity' => self::getSearchFieldMetadata()]); $form->addFormFieldsFromMetadata(); - CRM_Core_Form_Date::buildDateRange($form, 'activity_date', 1, '_low', '_high', ts('From'), FALSE, FALSE); - $form->addElement('hidden', 'activity_date_range_error'); - $form->addFormRule(array('CRM_Activity_BAO_Query', 'formRule'), $form); - $followUpActivity = array( 1 => ts('Yes'), 2 => ts('No'), @@ -631,27 +629,6 @@ public static function selectorReturnProperties() { return $properties; } - /** - * Custom form rules. - * - * @param array $fields - * @param array $files - * @param CRM_Core_Form $form - * - * @return bool|array - */ - public static function formRule($fields, $files, $form) { - $errors = array(); - - if (empty($fields['activity_date_low']) || empty($fields['activity_date_high'])) { - return TRUE; - } - - CRM_Utils_Rule::validDateRange($fields, 'activity_date', $errors, ts('Activity Date')); - - return empty($errors) ? TRUE : $errors; - } - /** * Where/qill clause for notes * diff --git a/CRM/Activity/Form/Search.php b/CRM/Activity/Form/Search.php index 93a2ae631ca5..d598dab992ab 100644 --- a/CRM/Activity/Form/Search.php +++ b/CRM/Activity/Form/Search.php @@ -322,31 +322,6 @@ public function fixFormValues() { } } - $dateLow = CRM_Utils_Request::retrieve('dateLow', 'String'); - - if ($dateLow) { - $dateLow = date('m/d/Y', strtotime($dateLow)); - $this->_formValues['activity_date_relative'] = 0; - $this->_defaults['activity_date_relative'] = 0; - $this->_formValues['activity_date_low'] = $dateLow; - $this->_defaults['activity_date_low'] = $dateLow; - } - - $dateHigh = CRM_Utils_Request::retrieve('dateHigh', 'String'); - - if ($dateHigh) { - // Activity date time assumes midnight at the beginning of the date - // This sets it to almost midnight at the end of the date - /* if ($dateHigh <= 99999999) { - $dateHigh = 1000000 * $dateHigh + 235959; - } */ - $dateHigh = date('m/d/Y', strtotime($dateHigh)); - $this->_formValues['activity_date_relative'] = 0; - $this->_defaults['activity_date_relative'] = 0; - $this->_formValues['activity_date_high'] = $dateHigh; - $this->_defaults['activity_date_high'] = $dateHigh; - } - // Enable search activity by custom value // @todo this is not good security practice. Instead define entity fields in metadata & // use getEntity Defaults diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index be480e7e77b9..085b4dfc525f 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -1899,6 +1899,8 @@ public function whereClauseSingle(&$values, $apiEntity = NULL) { case 'activity_date': case 'activity_date_low': case 'activity_date_high': + case 'activity_date_time_low': + case 'activity_date_time_high': case 'activity_role': case 'activity_status_id': case 'activity_status': diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index 597e54378852..a85cbb69dddb 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -1295,11 +1295,13 @@ public function addDateRange($name, $from = '_from', $to = '_to', $label = 'From * * @param string $fieldName * @param string $label + * @param bool $isDateTime + * Is this a date-time field (not just date). * @param bool $required * @param string $fromLabel * @param string $toLabel */ - public function addDatePickerRange($fieldName, $label, $required = FALSE, $fromLabel = 'From', $toLabel = 'To') { + public function addDatePickerRange($fieldName, $label, $isDateTime = FALSE, $required = FALSE, $fromLabel = 'From', $toLabel = 'To') { $options = array( '' => ts('- any -'), @@ -1314,7 +1316,7 @@ public function addDatePickerRange($fieldName, $label, $required = FALSE, $fromL NULL ); $attributes = ['format' => 'searchDate']; - $extra = ['time' => FALSE]; + $extra = ['time' => $isDateTime]; $this->add('datepicker', $fieldName . '_low', ts($fromLabel), $attributes, $required, $extra); $this->add('datepicker', $fieldName . '_high', ts($toLabel), $attributes, $required, $extra); } diff --git a/CRM/Core/Form/Search.php b/CRM/Core/Form/Search.php index 5d4ed98a0a3a..f793ae6f3ac1 100644 --- a/CRM/Core/Form/Search.php +++ b/CRM/Core/Form/Search.php @@ -154,9 +154,8 @@ public function addFormFieldsFromMetadata() { $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]); @@ -184,6 +183,10 @@ protected function getValidationTypeForField($entity, $fieldName) { 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 +207,15 @@ protected function getEntityDefaults($entity) { 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; diff --git a/templates/CRM/Activity/Form/Search/Common.tpl b/templates/CRM/Activity/Form/Search/Common.tpl index b260c49bb2ad..9df96580daab 100644 --- a/templates/CRM/Activity/Form/Search/Common.tpl +++ b/templates/CRM/Activity/Form/Search/Common.tpl @@ -89,10 +89,9 @@ - - - - {include file="CRM/Core/DateRange.tpl" fieldName="activity_date" from='_low' to='_high'} + + {include file="CRM/Core/DatePickerRange.tpl" fieldName="activity_date_time" from='_low' to='_high'} + From 7bab3351ddbf0f466a01133da7258f1a92734b49 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 4 Mar 2019 09:09:50 +1300 Subject: [PATCH 2/6] Add upgrade routine --- CRM/Upgrade/Incremental/SmartGroups.php | 40 +++++++++++++++++++ CRM/Upgrade/Incremental/php/FiveTwelve.php | 11 ++++- .../CRM/Upgrade/Incremental/BaseTest.php | 36 +++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/CRM/Upgrade/Incremental/SmartGroups.php b/CRM/Upgrade/Incremental/SmartGroups.php index 3c0500a6ec5c..764e12ab0818 100644 --- a/CRM/Upgrade/Incremental/SmartGroups.php +++ b/CRM/Upgrade/Incremental/SmartGroups.php @@ -111,6 +111,45 @@ protected function getConvertedDateValue($dateValue) { return $dateValue; } + /** + * Rename a smartgroup field. + * + * @param string $oldName + * @param string $newName + */ + public function renameField($oldName, $newName) { + foreach ($this->getSearchesWithField($oldName) as $savedSearch) { + $formValues = $savedSearch['form_values']; + foreach ($formValues as $index => $formValue) { + if ($formValue[0] === $oldName) { + $formValues[$index][0] = $newName; + } + } + + if ($formValues !== $savedSearch['form_values']) { + civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $formValues]); + } + } + } + + /** + * Rename pairs of fields + * + * @param array $pairs + * Array or arrays of pairs - e.g + * [ + * ['old' => 'activity_date', 'new' => 'activity_date_time'], + * ['old' => 'activity_date_low', 'new' => 'activity_date_time_low'], + * ['old' => 'activity_date_high', 'new' => 'activity_date_time_high'], + * ['old' => 'activity_date_relative', 'new' => 'activity_date_time_relative'], + * ] + */ + public function renameFields($pairs) { + foreach ($pairs as $pair) { + $this->renameField($pair['old'], $pair['new']); + } + } + /** * @param $field * @return mixed @@ -121,6 +160,7 @@ protected function getSearchesWithField($field) { 'form_values' => ['LIKE' => "%{$field}%"], ])['values']; return $savedSearches; + } } diff --git a/CRM/Upgrade/Incremental/php/FiveTwelve.php b/CRM/Upgrade/Incremental/php/FiveTwelve.php index e514d6532987..8202582bb4cb 100644 --- a/CRM/Upgrade/Incremental/php/FiveTwelve.php +++ b/CRM/Upgrade/Incremental/php/FiveTwelve.php @@ -73,10 +73,19 @@ public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) { * @param string $rev */ public function upgrade_5_12_alpha1($rev) { - $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev); + $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev); + $this->addTask('Update smart groups to rename filters on activity_date to activity_date_time', 'updateSmartGroups', [ + 'renameFields' => [ + ['old' => 'activity_date', 'new' => 'activity_date_time'], + ['old' => 'activity_date_low', 'new' => 'activity_date_time_low'], + ['old' => 'activity_date_high', 'new' => 'activity_date_time_high'], + ['old' => 'activity_date_relative', 'new' => 'activity_date_time_relative'], + ], + ]); $this->addTask('Update smart groups where jcalendar fields have been converted to datepicker', 'updateSmartGroups', [ 'datepickerConversion' => [ 'age_asof_date', + 'activity_date_time' ] ]); } diff --git a/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php b/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php index 362fd5babe49..20e4cefc11d1 100644 --- a/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php +++ b/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php @@ -124,6 +124,42 @@ public function testOnHoldConversion() { $savedSearch = $this->callAPISuccessGetSingle('SavedSearch', []); $this->assertEquals('IN', $savedSearch['form_values'][0][1]); $this->assertEquals(['1'], $savedSearch['form_values'][0][2]); + + } + + /** + * Test renaming a field. + */ + public function testRenameField() { + $this->callAPISuccess('SavedSearch', 'create', [ + 'form_values' => [ + ['activity_date_low', '=', '01/22/2019'], + ] + ]); + $smartGroupConversionObject = new CRM_Upgrade_Incremental_SmartGroups(); + $smartGroupConversionObject->renameField('activity_date_low', 'activity_date_time_low'); + $savedSearch = $this->callAPISuccessGetSingle('SavedSearch', []); + $this->assertEquals('activity_date_time_low', $savedSearch['form_values'][0][0]); + } + + /** + * Test renaming multiple fields. + */ + public function testRenameFields() { + $this->callAPISuccess('SavedSearch', 'create', [ + 'form_values' => [ + ['activity_date_low', '=', '01/22/2019'], + ['activity_date_relative', '=', 0], + ] + ]); + $smartGroupConversionObject = new CRM_Upgrade_Incremental_SmartGroups(); + $smartGroupConversionObject->renameFields([ + ['old' => 'activity_date_low', 'new' => 'activity_date_time_low'], + ['old' => 'activity_date_relative', 'new' => 'activity_date_time_relative'], + ]); + $savedSearch = $this->callAPISuccessGetSingle('SavedSearch', []); + $this->assertEquals('activity_date_time_low', $savedSearch['form_values'][0][0]); + $this->assertEquals('activity_date_time_relative', $savedSearch['form_values'][1][0]); } } From 929d5a15d5375f54a6476746e18e6e4b19aaa7cd Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 4 Mar 2019 11:09:16 +1300 Subject: [PATCH 3/6] Fix group conversion to add relative key Old format doesn't seem to have it --- CRM/Upgrade/Incremental/SmartGroups.php | 35 +++++++++++++++++-- .../CRM/Upgrade/Incremental/BaseTest.php | 9 ++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/CRM/Upgrade/Incremental/SmartGroups.php b/CRM/Upgrade/Incremental/SmartGroups.php index 764e12ab0818..4e54d874ee01 100644 --- a/CRM/Upgrade/Incremental/SmartGroups.php +++ b/CRM/Upgrade/Incremental/SmartGroups.php @@ -48,19 +48,42 @@ public function updateGroups($actions) { * @param array $fields */ public function datePickerConversion($fields) { - $fieldPossibilities = []; + $fieldPossibilities = $relativeFieldNames = []; foreach ($fields as $field) { $fieldPossibilities[] = $field; $fieldPossibilities[] = $field . '_high'; $fieldPossibilities[] = $field . '_low'; } + $relativeDateMappings = ['activity_date_time' => 'activity']; foreach ($fields as $field) { foreach ($this->getSearchesWithField($field) as $savedSearch) { $formValues = $savedSearch['form_values']; + $isRelative = $hasRelative = FALSE; + $relativeFieldName = $field . '_relative'; + + if (!empty($relativeDateMappings[$field]) && isset($formValues['relative_dates'])) { + if (!empty($formValues['relative_dates'][$relativeDateMappings[$field]])) { + $formValues[] = [$relativeFieldName, '=', $savedSearch['form_values']['relative_dates'][$relativeDateMappings[$field]]]; + unset($formValues['relative_dates'][$relativeDateMappings[$field]]); + $isRelative = TRUE; + } + } foreach ($formValues as $index => $formValue) { if (in_array($formValue[0], $fieldPossibilities)) { - $formValues[$index][2] = $this->getConvertedDateValue($formValue[2]); + if ($isRelative) { + unset($formValues[$index]); + } + else { + $isHigh = substr($formValue[0], -5, 5) === '_high'; + $formValues[$index][2] = $this->getConvertedDateValue($formValue[2], $isHigh); + } + } + } + if (!$isRelative) { + if (!in_array($relativeFieldName, $relativeFieldNames)) { + $relativeFieldNames[] = $relativeFieldName; + $formValues[] = [$relativeFieldName, '=', 0]; } } if ($formValues !== $savedSearch['form_values']) { @@ -98,15 +121,21 @@ public function convertEqualsStringToInArray($field) { * Get converted date value. * * @param string $dateValue + * @param bool $isEndOfDay + * Is this the upper value in a search range? If so alter the time to + * get the end of day if none set. * * @return string * $dateValue */ - protected function getConvertedDateValue($dateValue) { + protected function getConvertedDateValue($dateValue, $isEndOfDay) { if (date('Y-m-d', strtotime($dateValue)) !== $dateValue && date('Y-m-d H:i:s', strtotime($dateValue)) !== $dateValue ) { $dateValue = date('Y-m-d H:i:s', strtotime(CRM_Utils_Date::processDate($dateValue))); + if ($isEndOfDay) { + $dateValue = str_replace('00:00:00', '23:59:59', $dateValue); + } } return $dateValue; } diff --git a/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php b/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php index 20e4cefc11d1..3827a8c2c7a7 100644 --- a/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php +++ b/tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php @@ -105,9 +105,16 @@ public function testSmartGroupDatePickerConversion() { ]); $savedSearch = $this->callAPISuccessGetSingle('SavedSearch', []); $this->assertEquals('grant_application_received_date_high', $savedSearch['form_values'][0][0]); - $this->assertEquals('2019-01-20 00:00:00', $savedSearch['form_values'][0][2]); + $this->assertEquals('2019-01-20 23:59:59', $savedSearch['form_values'][0][2]); $this->assertEquals('grant_due_date_low', $savedSearch['form_values'][1][0]); $this->assertEquals('2019-01-22 00:00:00', $savedSearch['form_values'][1][2]); + $hasRelative = FALSE; + foreach ($savedSearch['form_values'] as $form_value) { + if ($form_value[0] === 'grant_due_date_relative') { + $hasRelative = TRUE; + } + } + $this->assertEquals(TRUE, $hasRelative); } /** From 2307be0897da1b4090cbb2783a239aebd30fc047 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 4 Mar 2019 13:47:35 +1300 Subject: [PATCH 4/6] Add form rule for chronological ordeR --- CRM/Core/Form/Search.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CRM/Core/Form/Search.php b/CRM/Core/Form/Search.php index f793ae6f3ac1..c0defa2ac521 100644 --- a/CRM/Core/Form/Search.php +++ b/CRM/Core/Form/Search.php @@ -151,6 +151,7 @@ public function buildQuickform() { * 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) { @@ -164,6 +165,31 @@ public function addFormFieldsFromMetadata() { } } + /** + * Global validation rules for the form. + * + * @param array $fields + * Posted values of the form. + * + * @return array + * list of errors to be posted back to the form + */ + public static function formRule($fields, $files, $form) { + $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. * From d7ea25cdc18285725d68244428c76f43ed65b0ff Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 4 Mar 2019 14:54:29 +1300 Subject: [PATCH 5/6] Fix related search classes to have the same signature --- CRM/Contact/Form/Search/Basic.php | 2 +- CRM/Pledge/Form/Search.php | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/CRM/Contact/Form/Search/Basic.php b/CRM/Contact/Form/Search/Basic.php index 4aa415d44742..c68343686fa5 100644 --- a/CRM/Contact/Form/Search/Basic.php +++ b/CRM/Contact/Form/Search/Basic.php @@ -200,7 +200,7 @@ public function postProcess() { * * @return array|bool */ - public static function formRule($fields) { + public static function formRule($fields, $files, $form) { // check actionName and if next, then do not repeat a search, since we are going to the next page if (array_key_exists('_qf_Search_next', $fields)) { if (empty($fields['task'])) { diff --git a/CRM/Pledge/Form/Search.php b/CRM/Pledge/Form/Search.php index 3d00901f122c..0073fabcf5d2 100644 --- a/CRM/Pledge/Form/Search.php +++ b/CRM/Pledge/Form/Search.php @@ -313,24 +313,6 @@ public function addRules() { $this->addFormRule(array('CRM_Pledge_Form_Search', 'formRule')); } - /** - * Global validation rules for the form. - * - * @param array $fields - * Posted values of the form. - * - * @return array|bool - */ - public static function formRule($fields) { - $errors = array(); - - if (!empty($errors)) { - return $errors; - } - - return TRUE; - } - /** * Set the default form values. * From 8e80025cb875549eaadc204dbe0e5634123bc35c Mon Sep 17 00:00:00 2001 From: eileen Date: Wed, 6 Mar 2019 10:30:33 +1300 Subject: [PATCH 6/6] Add enotice handling for weird s....' --- CRM/Upgrade/Incremental/SmartGroups.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CRM/Upgrade/Incremental/SmartGroups.php b/CRM/Upgrade/Incremental/SmartGroups.php index 4e54d874ee01..64c5ab9dc0ae 100644 --- a/CRM/Upgrade/Incremental/SmartGroups.php +++ b/CRM/Upgrade/Incremental/SmartGroups.php @@ -70,6 +70,10 @@ public function datePickerConversion($fields) { } } foreach ($formValues as $index => $formValue) { + if (!isset($formValue[0])) { + // Any actual criteria will have this key set but skip any weird lines + continue; + } if (in_array($formValue[0], $fieldPossibilities)) { if ($isRelative) { unset($formValues[$index]);