Improve the logic of recurring ranges (#185)
This commit is contained in:
parent
82aa988db4
commit
ea868e3cd3
2 changed files with 159 additions and 21 deletions
|
@ -59,6 +59,11 @@ class element extends \mod_customcert\element {
|
|||
*/
|
||||
const LAST_YEAR_PLACEHOLDER = '{{last_year}}';
|
||||
|
||||
/**
|
||||
* A year in the user's date.
|
||||
*/
|
||||
const DATE_YEAR_PLACEHOLDER = '{{date_year}}';
|
||||
|
||||
/**
|
||||
* Default max number of dateranges per element.
|
||||
*/
|
||||
|
@ -428,19 +433,19 @@ class element extends \mod_customcert\element {
|
|||
* @return string
|
||||
*/
|
||||
protected function get_daterange_string($date) {
|
||||
$rangematched = null;
|
||||
$matchedrange = null;
|
||||
$outputstring = '';
|
||||
|
||||
foreach ($this->get_decoded_data()->dateranges as $key => $range) {
|
||||
if ($this->is_date_in_range($date, $range)) {
|
||||
$rangematched = $range;
|
||||
$outputstring = $range->datestring;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($range->recurring)) {
|
||||
if ($rangematched = $this->get_matched_recurring_range($date, $range)) {
|
||||
$outputstring = $rangematched->datestring;
|
||||
if ($this->is_recurring_range($range)) {
|
||||
if ($matchedrange = $this->get_matched_recurring_range($date, $range)) {
|
||||
$outputstring = $matchedrange->datestring;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ($this->is_date_in_range($date, $range)) {
|
||||
$matchedrange = $range;
|
||||
$outputstring = $range->datestring;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +455,16 @@ class element extends \mod_customcert\element {
|
|||
$outputstring = $this->get_decoded_data()->fallbackstring;
|
||||
}
|
||||
|
||||
return $this->format_date_string($outputstring, $rangematched);
|
||||
return $this->format_date_string($outputstring, $date, $matchedrange);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass $range Range object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_recurring_range(\stdClass $range) {
|
||||
return !empty($range->recurring);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -466,7 +480,84 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get recurring date range matched provided date.
|
||||
* Check if provided date is in the recurring date range.
|
||||
*
|
||||
* @param int $date Unix timestamp date to check.
|
||||
* @param \stdClass $range Range object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_date_in_recurring_range($date, \stdClass $range) {
|
||||
$intdate = $this->build_number_from_date($date);
|
||||
$intstart = $this->build_number_from_date($range->startdate);
|
||||
$intend = $this->build_number_from_date($range->enddate);
|
||||
|
||||
if (!$this->has_turn_of_the_year($range)) {
|
||||
if ($intdate >= $intstart && $intdate <= $intend) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($intdate >= $intstart && $intdate >= $intend) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($intdate <= $intstart && $intdate <= $intend) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if provided recurring range has a turn of the year.
|
||||
*
|
||||
* @param \stdClass $reccurringrange Range object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function has_turn_of_the_year(\stdClass $reccurringrange) {
|
||||
return date('Y', $reccurringrange->startdate) != date('Y', $reccurringrange->enddate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if provided date is in the start year of the recurring range with a turn of the year.
|
||||
*
|
||||
* @param int $date Unix timestamp date to check.
|
||||
* @param \stdClass $range Range object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function in_start_year($date, \stdClass $range) {
|
||||
$intdate = $this->build_number_from_date($date);
|
||||
$intstart = $this->build_number_from_date($range->startdate);
|
||||
$intend = $this->build_number_from_date($range->enddate);
|
||||
|
||||
return $intdate >= $intstart && $intdate >= $intend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if provided date is in the end year of the recurring range with a turn of the year.
|
||||
*
|
||||
* @param int $date Unix timestamp date to check.
|
||||
* @param \stdClass $range Range object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function in_end_year($date, \stdClass $range) {
|
||||
$intdate = $this->build_number_from_date($date);
|
||||
$intstart = $this->build_number_from_date($range->startdate);
|
||||
$intend = $this->build_number_from_date($range->enddate);
|
||||
|
||||
return $intdate <= $intstart && $intdate <= $intend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return matched recurring date range.
|
||||
*
|
||||
* As recurring date ranges do not depend on the year,
|
||||
* we will use a date's year to build a new matched recurring date range with
|
||||
* start year and end year. This is required to replace placeholders like first_year and last_year.
|
||||
*
|
||||
* @param int $date Unix timestamp date to check.
|
||||
* @param \stdClass $range Range object.
|
||||
|
@ -474,34 +565,68 @@ class element extends \mod_customcert\element {
|
|||
* @return \stdClass || null
|
||||
*/
|
||||
protected function get_matched_recurring_range($date, \stdClass $range) {
|
||||
while ($range->enddate < time()) {
|
||||
$startyear = date('Y', $range->startdate) + 1; // Max recurring period is 12 months.
|
||||
$endyear = date('Y', $range->enddate) + 1; // Max recurring period is 12 months.
|
||||
if (!$this->is_date_in_recurring_range($date, $range)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$range->startdate = strtotime(date('d.m.', $range->startdate) . $startyear);
|
||||
$range->enddate = strtotime(date('d.m.', $range->enddate) . $endyear);
|
||||
if ($this->has_turn_of_the_year($range)) {
|
||||
|
||||
if ($this->in_start_year($date, $range)) {
|
||||
$startyear = date('Y', $date);
|
||||
$endyear = $startyear + 1;
|
||||
$range->startdate = strtotime(date('d.m.', $range->startdate) . $startyear);
|
||||
$range->enddate = strtotime(date('d.m.', $range->enddate) . $endyear);
|
||||
|
||||
if ($this->is_date_in_range($date, $range)) {
|
||||
return $range;
|
||||
}
|
||||
|
||||
if ($this->in_end_year($date, $range)) {
|
||||
$endyear = date('Y', $date);
|
||||
$startyear = $endyear - 1;
|
||||
$range->startdate = strtotime(date('d.m.', $range->startdate) . $startyear);
|
||||
$range->enddate = strtotime(date('d.m.', $range->enddate) . $endyear);
|
||||
|
||||
return $range;
|
||||
}
|
||||
} else {
|
||||
$range->startdate = strtotime(date('d.m.', $range->startdate) . date('Y', $date));
|
||||
$range->enddate = strtotime(date('d.m.', $range->enddate) . date('Y', $date));
|
||||
|
||||
return $range;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date string.
|
||||
* Build number representation of the provided date.
|
||||
*
|
||||
* @param int $date Unix timestamp date to check.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function build_number_from_date($date) {
|
||||
return (int)date('md', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date string based on different types of placeholders.
|
||||
*
|
||||
* @param string $datestring Date string to format.
|
||||
* @param int $date Unix timestamp date to check.
|
||||
* @param \stdClass $range Optional range element element to process range related placeholders.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function format_date_string($datestring, $range = null) {
|
||||
protected function format_date_string($datestring, $date, $range = null) {
|
||||
foreach ($this->get_placeholders() as $search => $replace) {
|
||||
$datestring = str_replace($search, $replace, $datestring);
|
||||
}
|
||||
|
||||
foreach ($this->get_date_placeholders($date) as $search => $replace) {
|
||||
$datestring = str_replace($search, $replace, $datestring);
|
||||
}
|
||||
|
||||
if ($range) {
|
||||
foreach ($this->get_range_placeholders($range) as $search => $replace) {
|
||||
$datestring = str_replace($search, $replace, $datestring);
|
||||
|
@ -522,6 +647,19 @@ class element extends \mod_customcert\element {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of user's date related placeholders to replace in date string as search => $replace pairs.
|
||||
|
||||
* @param int $date Unix timestamp date to check.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_date_placeholders($date) {
|
||||
return [
|
||||
self::DATE_YEAR_PLACEHOLDER => date('Y', $date),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of range related placeholders to replace in date string as search => $replace pairs.
|
||||
*
|
||||
|
|
|
@ -33,7 +33,7 @@ $string['dateitem_help'] = 'This will be the date that is printed on the certifi
|
|||
$string['dateranges'] = 'Dateranges';
|
||||
$string['fallbackstring'] = 'Fallback string';
|
||||
$string['fallbackstring_help'] = 'This string will be displayed if no daterange applies to a date. If Fallback string is not set, then there will be no output at all.';
|
||||
$string['help'] = 'Configure a string representation for each daterange. Set start and end dates as well as a string you would like to transform each range to. Make sure your ranges do not overlap, otherwise the first detected daterange will be applied. If no daterange applied to a date, then Fallback string will be displayed. If Fallback string is not set, then there will be no output at all. If you mark a date range as Recurring, then the configured year will not be considered and the current year will be used. As the year of a recurring date range is not considered, you are not allowed to configure a recurring date range with more than 12 months as it would become ambiguous otherwise. Also there are {{first_year}} and {{last_year}} and {{current_year}} placeholders that could be used in the string representation. The placeholders will be replaced by first year or last year in the matched range or the current year.';
|
||||
$string['help'] = 'Configure a string representation for each daterange. Set start and end dates as well as a string you would like to transform each range to. Make sure your ranges do not overlap, otherwise the first detected daterange will be applied. If no daterange applied to a date, then Fallback string will be displayed. If Fallback string is not set, then there will be no output at all. If you mark a date range as Recurring, then the configured year will not be considered and the current year will be used. As the year of a recurring date range is not considered, you are not allowed to configure a recurring date range with more than 12 months as it would become ambiguous otherwise. Also there are {{first_year}}, {{last_year}}, {{current_year}} and {{date_year}} placeholders that could be used in the string representation. The placeholders will be replaced by first year or last year in the matched range or the current year or a year from the users\'s date.';
|
||||
$string['issueddate'] = 'Issued date';
|
||||
$string['maxranges'] = 'Maximum number ranges';
|
||||
$string['maxranges_desc'] = 'Set a maximum number of date ranges per each element';
|
||||
|
|
Loading…
Reference in a new issue