diff --git a/web/sites/all/modules/date/date_api/date_api_ical.inc b/web/sites/all/modules/date/date_api/date_api_ical.inc index 4911298..b1b5830 100644 --- a/web/sites/all/modules/date/date_api/date_api_ical.inc +++ b/web/sites/all/modules/date/date_api/date_api_ical.inc @@ -760,6 +760,10 @@ function date_api_ical_build_rrule($form_values) { $rrule .= ';COUNT=' . $form_values['COUNT']; } + if (array_key_exists('NEVER', $form_values)) { + $rrule .= ';NEVER=' . $form_values['NEVER']; + } + // iCal rules presume the week starts on Monday unless otherwise specified, // so we'll specify it. if (array_key_exists('WKST', $form_values)) { diff --git a/web/sites/all/modules/date/date_repeat/date_repeat.module b/web/sites/all/modules/date/date_repeat/date_repeat.module index 61d971b..f5c4dd4 100644 --- a/web/sites/all/modules/date/date_repeat/date_repeat.module +++ b/web/sites/all/modules/date/date_repeat/date_repeat.module @@ -68,6 +68,124 @@ function date_repeat_interval_options() { } /** + * Implements hook_cron(). + * + * Create new date entries in the future for never ending repeating dates. + */ +function date_repeat_cron() { + module_load_include('inc', 'date_api', 'date_api_ical'); + $query = db_query("select field_config_instance.field_name,field_config_instance.entity_type,field_config_instance.bundle,field_config.type,field_config.data from {field_config_instance} field_config_instance left join {field_config} field_config on field_config.field_name=field_config_instance.field_name where field_config.module='date' and field_config.type in ('datetime', 'date', 'datestamp')"); + foreach($query as $row) { + $data = unserialize($row->data); + if(isset($data['settings']['repeat']) && $data['settings']['repeat'] == 1 && $data['settings']['cache_enabled'] == 1) { + date_repeat_process_repeat_date_field($row->field_name, $row->type, $row->entity_type, $row->bundle, $data); + } + } +} + +/** + * Helper function for date_repeat_cron(). + */ +function date_repeat_process_repeat_date_field($field_name, $field_type, $entity_type, $bundle, $data) { + if ($entity_type == 'node') { + $nids = db_query("select nid from {node} where type=:type", array(':type' => $bundle)); + foreach ($nids as $nid) { + $entity = node_load($nid->nid); + date_repeat_process_repeat_date_entity($entity, $field_name, $field_type, $entity_type, $bundle, $data); + } + } +} + +/** + * Helper function for date_repeat_process_repeat_date_field(). + */ +function date_repeat_process_repeat_date_entity($entity, $field_name, $field_type, $entity_type, $bundle, $data) { + $languagecode = 'und'; + if (isset($entity->{$field_name}[$languagecode][0]['rrule']) && $entity->{$field_name}[$languagecode][0]['rrule']) { + $rruletext = $entity->{$field_name}[$languagecode][0]['rrule']; + $parts = explode("\n", $rruletext); + if (count($parts)) { + $rruletext = $parts[0]; + } + // Get the parsed array of rule values. + $rrule = date_ical_parse_rrule('RRULE:', $rruletext); + if (isset($rrule['NEVER'][0]) && $rrule['NEVER'][0] && strtotime($rrule['NEVER'][0])) { + date_repeat_process_repeat_date_entity_never_field($entity, $field_name, $field_type, $entity_type, $bundle, $data, $languagecode, $rrule['NEVER'][0], $rruletext); + } + } +} + +/** + * Helper function for date_repeat_process_repeat_date_entity_never_field(). + */ +function date_repeat_process_repeat_date_entity_never_field($entity, $field_name, $field_type, $entity_type, $bundle, $data, $languagecode, $NEVER, $rruletext) { + $field_count = count($entity->{$field_name}[$languagecode]); + $lastdate = $entity->{$field_name}[$languagecode][$field_count-1]['value']; + $endday_time = strtotime($NEVER); + + switch($field_type) { + case 'date': + $lastdate = str_replace('T', ' ', $lastdate); + $lastdate = strtotime($lastdate); + $endday = date('Y-m-d', $endday_time).'T'.date('H:i:s', $endday_time); + break; + case 'datetime': + $lastdate = strtotime($lastdate); + $endday = date('Y-m-d H:i:s', $endday_time); + break; + case 'datestamp': + $endday = $endday_time; + break; + } + + $timezone_db = date_get_timezone_db($data['settings']['tz_handling']); + $endday = new DateObject($endday, $timezone_db, date_type_format($field_type)); + $endday_datetime = date_format($endday, DATE_FORMAT_DATETIME); + $data['type'] = $field_type; + $data['field_name'] = $field_name; + $item = $entity->{$field_name}[$languagecode][$field_count-1]; + unset($item['db']); + $dates = date_repeat_build_dates($rruletext, null, $data, $item, $endday_datetime); + array_shift($dates); + + if ($dates && count($dates) > 0) { + $tablename = 'field_data_'.$field_name; + $revision_tablename = 'field_revision_'.$field_name; + $lastrow = db_query("select * from {".$tablename."} where entity_type=:entity_type and bundle=:bundle and revision_id=:revision_id order by delta desc limit 0,1", array(':entity_type' => $entity_type, ':bundle' => $bundle, ':revision_id' => $entity->vid))->fetchObject(); + $delta = $lastrow->delta; + + $insertdata = array( + ':entity_type' => $lastrow->entity_type, + ':bundle' => $lastrow->bundle, + ':deleted' => $lastrow->deleted, + ':entity_id' => $lastrow->entity_id, + ':revision_id' => $lastrow->revision_id, + ':language' => $lastrow->language, + ':delta' => $delta, + ); + + foreach($dates as $date) { + $delta++; + $insertdata[':value'] = $date['value']; + $insertdata[':rrule'] = $date['rrule']; + $insertdata[':delta'] = $delta; + + if($data['settings']['todate']) { + $insertdata[':value2'] = $date['value2']; + db_query("insert into {".$tablename."} (entity_type,bundle,deleted,entity_id,revision_id,language,delta,".$field_name."_value,".$field_name."_value2, ".$field_name."_rrule) values (:entity_type,:bundle,:deleted,:entity_id,:revision_id,:language,:delta, :value, :value2, :rrule)", $insertdata); + db_query("insert into {".$revision_tablename."} (entity_type,bundle,deleted,entity_id,revision_id,language,delta,".$field_name."_value,".$field_name."_value2, ".$field_name."_rrule) values (:entity_type,:bundle,:deleted,:entity_id,:revision_id,:language,:delta, :value, :value2, :rrule)", $insertdata); + } + else { + db_query("insert into {".$tablename."} (entity_type,bundle,deleted,entity_id,revision_id,language,delta,".$field_name."_value, ".$field_name."_rrule) values (:entity_type,:bundle,:deleted,:entity_id,:revision_id,:language,:delta, :value, :rrule)", $insertdata); + db_query("insert into {".$revision_tablename."} (entity_type,bundle,deleted,entity_id,revision_id,language,delta,".$field_name."_value, ".$field_name."_rrule) values (:entity_type,:bundle,:deleted,:entity_id,:revision_id,:language,:delta, :value, :rrule)", $insertdata); + } + } + + db_query("delete from {cache_field} where cid=:cid", array('cid' => 'field:node:'.$entity->nid)); + } +} + +/** * Helper function for FREQ options. * * Translated and untranslated arrays of the iCal day of week names. diff --git a/web/sites/all/modules/date/date_repeat/date_repeat_form.inc b/web/sites/all/modules/date/date_repeat/date_repeat_form.inc index 3352595..f5bf27c 100644 --- a/web/sites/all/modules/date/date_repeat/date_repeat_form.inc +++ b/web/sites/all/modules/date/date_repeat/date_repeat_form.inc @@ -82,6 +82,11 @@ function _date_repeat_rrule_process($element, &$form_state, $form) { $count = $merged_values['COUNT']; } + $never = '1 year'; + if (!empty($merged_values['NEVER'])) { + $never = $merged_values['NEVER']; + } + $element['FREQ'] = array( '#type' => 'select', '#title' => t('Repeats', array(), array('context' => 'Date repeat')), @@ -522,10 +527,27 @@ function _date_repeat_rrule_process($element, &$form_state, $form) { ), ); + $never_prefix = '
' . t('Never', array(), array('context' => 'Date repeat')) . '
'.'
'.t('Automatically create new entries this far into the future during cron runs.', array(), array('context' => 'Date repeat')).'
'; + $never_suffix = '
'.t('Format: PHP strtotime format.', array(), array('context' => 'Date repeat')).'
'; + + $never_form_element = array( + '#type' => 'textfield', + '#title' => t('Never', array(), array('context' => 'Date repeat')), + '#default_value' => $never, + '#prefix' => $never_prefix, + '#suffix' => $never_suffix, + '#size' => 10, + '#maxlength' => 10, + ); + $range_of_repeat_default = 'COUNT'; if (!empty($until)) { $range_of_repeat_default = 'UNTIL'; } + if (!empty($never)) { + $range_of_repeat_default = 'NEVER'; + } + $element['range_of_repeat'] = array( '#type' => 'date_repeat_form_element_radios', '#tree' => TRUE, @@ -542,9 +564,11 @@ function _date_repeat_rrule_process($element, &$form_state, $form) { '#options' => array( 'COUNT' => t('Count'), 'UNTIL' => t('Until'), + 'NEVER' => t('Never'), ), 'count_child' => $count_form_element, 'until_child' => $until_form_element, + 'never_child' => $never_form_element, '#div_classes' => array( 'container-inline count', "until widget-{$element['#date_repeat_widget']} label-{$element['#date_label_position']}", @@ -895,11 +919,15 @@ function date_repeat_merge($form_values, $element) { case 'UNTIL': $form_values['UNTIL'] = $form_values['until_child']; break; + case 'NEVER': + $form_values['NEVER'] = $form_values['never_child']; + break; } } unset($form_values['count_child']); unset($form_values['until_child']); + unset($form_values['never_child']); if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) { unset($form_values['BYDAY']['']); diff --git a/web/sites/all/modules/date/date_repeat_field/date_repeat_field.module b/web/sites/all/modules/date/date_repeat_field/date_repeat_field.module index d4d4c90..3655dd2 100644 --- a/web/sites/all/modules/date/date_repeat_field/date_repeat_field.module +++ b/web/sites/all/modules/date/date_repeat_field/date_repeat_field.module @@ -373,6 +373,20 @@ function date_repeat_field_widget_validate($element, &$form_state) { form_set_error($error_field_count, t("Missing value in 'Range of repeat'. (COUNT).", array(), array('context' => 'Date repeat'))); } + $error_field_never = $error_field_base . '][rrule][never_child'; + if (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'NEVER' && empty($rrule_values['NEVER'])) { + form_set_error($error_field_never, t("Missing value in 'Range of repeat'. (NEVER).", array(), array('context' => 'Date repeat'))); + } + elseif (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'NEVER' && $rrule_values['NEVER']) { + $output = strtotime($rrule_values['NEVER']); + if (!$output) { + form_set_error($error_field_never, t("Wrong date/time value in 'Range of repeat'. (NEVER).", array(), array('context' => 'Date repeat'))); + } + else { + $rrule_values['NEVER_time'] = $output - time(); + } + } + if (form_get_errors()) { return; } @@ -433,7 +447,7 @@ function date_repeat_after_build(&$element, &$form_state) { * whichever is missing will be created when needed. */ // @codingStandardsIgnoreStart -function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) { +function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item, $end_datetime = FALSE) { // @codingStandardsIgnoreEnd include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc'; $field_name = $field['field_name']; @@ -473,11 +487,33 @@ function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $i elseif (!empty($rrule_values['COUNT'])) { $end_datetime = NULL; } + elseif (!empty($rrule_values['NEVER'])) { + // Don't return if we have a NEVER. + } else { // No UNTIL and no COUNT? return array(); } + if (!$end_datetime) { + if (!empty($rrule_values['UNTIL']['datetime'])) { + $end = date_ical_date($rrule_values['UNTIL'], $timezone); + $end_datetime = date_format($end, DATE_FORMAT_DATETIME); + } + elseif (!empty($rrule_values['COUNT'])) { + $end_datetime = NULL; + } + elseif (!empty($rrule_values['NEVER'])) { + $never_opt = array('datetime' => date('Y-m-d H:i:s', strtotime((is_array($rrule_values['NEVER']) ? $rrule_values['NEVER'][0] : $rrule_values['NEVER']))), 'tz' => null); + $end = date_ical_date($never_opt, $timezone); + $end_datetime = date_format($end, DATE_FORMAT_DATETIME); + } + else { + // No UNTIL and no COUNT? + return array(); + } + } + // Split the RRULE into RRULE, EXDATE, and RDATE parts. $parts = date_repeat_split_rrule($rrule); $parsed_exceptions = (array) $parts[1];