Index: branches/5.2.x/core/units/helpers/cron_helper.php =================================================================== diff -u -N -r16513 -r16769 --- branches/5.2.x/core/units/helpers/cron_helper.php (.../cron_helper.php) (revision 16513) +++ branches/5.2.x/core/units/helpers/cron_helper.php (.../cron_helper.php) (revision 16769) @@ -1,6 +1,6 @@ fieldFactory = new FieldFactory(); + } + + /** * Defines possible cron fields and their matching priority * * @var Array @@ -193,6 +214,26 @@ } /** + * Get an instance of a field object for a cron expression field type. + * + * @param integer $field_type Field type. + * + * @return FieldInterface + */ + protected function getField($field_type) + { + $field_mapping = array( + self::MINUTE => 0, + self::HOUR => 1, + self::DAY => 2, + self::MONTH => 3, + self::WEEKDAY => 4, + ); + + return $this->fieldFactory->getField($field_mapping[$field_type]); + } + + /** * Creates virtual fields for given unit * * @param string $prefix @@ -252,13 +293,12 @@ { $validated = true; $combined_value = Array (); - $cron_field = new kCronField(); foreach ($this->fieldTypes as $field_type) { $field_name = $this->_getFieldNameByType($field_type, $field_prefix); $value = preg_replace('/\s+/s', '', mb_strtoupper($object->GetDBField($field_name))); - if ( $cron_field->validate($field_type, $value) ) { + if ( $this->getField($field_type)->validate($value) ) { $object->SetDBField($field_name, $value); } else { @@ -276,36 +316,6 @@ } /** - * Replaces aliases in the field - * - * @param int $field_type - * @param string $value - * @return string - * @access public - */ - public static function replaceAliases($field_type, $value) - { - $replacements = Array (); - $value = mb_strtolower($value); - - if ( $field_type == self::MONTH ) { - $replacements = Array ( - 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'may' => 5, 'jun' => 6, - 'jul' => 7, 'aug' => 8, 'sep' => 9, 'oct' => 10, 'nov' => 11, 'dec' => 12, - ); - } - elseif ( $field_type == self::WEEKDAY ) { - $replacements = Array ('sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, 'thu' => 4, 'fri' => 5, 'sat' => 6); - } - - if ( $replacements ) { - $value = str_replace(array_keys($replacements), array_values($replacements), $value); - } - - return $value; - } - - /** * Returns next (after given one or now) timestamp matching given cron expression * * @param string $expression @@ -322,359 +332,15 @@ $date = TIMENOW; } - $next_run = strtotime('-' . (int)adodb_date('s', $date) . ' seconds', $date); - $expression_parts = explode(' ', $expression); + $cron = CronExpression::factory($expression); - $cron_field = new kCronField(); + $date_formatted = date('Y-m-d H:i:s', $date); - // set a hard limit to bail on an impossible date - for ($i = 0; $i < 1000; $i++) { - foreach ($this->fieldTypes as $field_type) { - $matched = false; - $part = $expression_parts[$field_type - 1]; - - // check if this is singular or a list - if ( strpos($part, ',') === false ) { - $matched = $cron_field->match($field_type, $next_run, $part); - } - else { - $rules = explode(',', $part); - - foreach ($rules as $rule) { - if ( $cron_field->match($field_type, $next_run, $rule) ) { - $matched = true; - break; - } - } - } - - // if the field is not matched, then start over - if ( !$matched ) { - $next_run = $cron_field->increment($field_type, $next_run, $inverse); - continue 2; - } - } - - // Skip this match if needed - if ( (!$allow_current_date && $next_run == $date) ) { - $next_run = $cron_field->increment(self::MINUTE, $next_run, $inverse); - continue; - } - - return $next_run; + if ( $inverse ) { + return $cron->getPreviousRunDate($date_formatted, 0, $allow_current_date)->format('U'); } - throw new RuntimeException('Impossible CRON expression'); + return $cron->getNextRunDate($date_formatted, 0, $allow_current_date)->format('U'); } -} - -class kCronField extends kBase { - - /** - * Validates field value - * - * @param int $field_type - * @param string $value - * @param bool $asterisk_allowed - * @return bool - * @access public - */ - public function validate($field_type, $value, $asterisk_allowed = true) - { - $rules = explode(',', kCronHelper::replaceAliases($field_type, $value)); - - foreach ($rules as $rule) { - if ( $this->_isIncrementRule($rule) ) { - if ( !$this->_validateIncrementRule($field_type, $rule) ) { - return false; - } - } - elseif ( $this->_isRangeRule($rule) ) { - if ( !$this->_validateRangeRule($field_type, $rule) ) { - return false; - } - } - elseif ( !$this->_validateNumberRule($field_type, $rule, $asterisk_allowed) ) { - return false; - } - } - - return true; - } - - /** - * Determines if expression is range - * - * @param string $rule - * @return bool - * @access protected - */ - protected function _isRangeRule($rule) - { - return strpos($rule, '-') !== false; - } - - /** - * Validates range rule - * - * @param int $field_type - * @param string $rule - * @return bool - * @access protected - */ - protected function _validateRangeRule($field_type, $rule) - { - $parts = explode('-', $rule); - - if ( count($parts) != 2 ) { - return false; - } - - $min_value = $parts[0]; - $max_value = $parts[1]; - - if ( !$this->_validateNumberRule($field_type, $min_value) || !$this->_validateNumberRule($field_type, $max_value) || $min_value >= $max_value ) { - return false; - } - - return true; - } - - /** - * Determines if expression is increment - * - * @param string $rule - * @return bool - * @access protected - */ - protected function _isIncrementRule($rule) - { - return strpos($rule, '/') !== false; - } - - /** - * Validates increment rule - * - * @param int $field_type - * @param string $rule - * @return bool - * @access protected - */ - protected function _validateIncrementRule($field_type, $rule) - { - $parts = explode('/', $rule); - - if ( count($parts) != 2 ) { - return false; - } - - $interval = $parts[0]; - $increment = $parts[1]; - - if ( $this->_isRangeRule($interval) ) { - if ( !$this->_validateRangeRule($field_type, $interval) ) { - return false; - } - } - elseif ( !$this->_validateNumberRule($field_type, $interval, true) ) { - return false; - } - - if ( !$this->_validateNumberRule($field_type, $increment) ) { - return false; - } - - return true; - } - - /** - * Validates, that number within range OR an asterisk is given - * - * @param int $field_type - * @param string $rule - * @param bool $asterisk_allowed - * @return bool - * @access protected - */ - protected function _validateNumberRule($field_type, $rule, $asterisk_allowed = false) - { - if ( "$rule" === '*' ) { - return $asterisk_allowed; - } - - $int_rule = (int)$rule; - - if ( !is_numeric($rule) || "$int_rule" !== "$rule" ) { - // not integer - return false; - } - - $range_mapping = Array ( - kCronHelper::MINUTE => Array ('from' => 0, 'to' => 59), - kCronHelper::HOUR => Array ('from' => 0, 'to' => 23), - kCronHelper::DAY => Array ('from' => 1, 'to' => 31), - kCronHelper::MONTH => Array ('from' => 1, 'to' => 12), - kCronHelper::WEEKDAY => Array ('from' => 0, 'to' => 7), - ); - - return $int_rule >= $range_mapping[$field_type]['from'] && $int_rule <= $range_mapping[$field_type]['to']; - } - - /** - * Tries to match given date to given expression - * - * @param int $field_type - * @param int $date - * @param string $rule - * @return bool - * @access public - */ - public function match($field_type, $date, $rule) - { - $date_part = $this->_getDatePart($field_type, $date, $rule); - - if ( $this->_isIncrementRule($rule) ) { - return $this->_isInIncrement($date_part, $rule); - } - elseif ( $this->_isRangeRule($rule) ) { - return $this->_isInRange($date_part, $rule); - } - - return $rule == '*' || $date_part == $rule; - } - - /** - * Returns only part, needed based on field type of date in timestamp - * - * @param int $field_type - * @param int $date - * @param string $rule - * @return int - * @access protected - */ - protected function _getDatePart($field_type, $date, $rule) - { - $mapping = Array ( - kCronHelper::MINUTE => 'i', - kCronHelper::HOUR => 'G', - kCronHelper::DAY => 'j', - kCronHelper::MONTH => 'n', - kCronHelper::WEEKDAY => 'N', - ); - - if ( $field_type == kCronHelper::WEEKDAY ) { - // Test to see which Sunday to use -- 0 == 7 == Sunday - $mapping[$field_type] = in_array(7, str_split($rule)) ? 'N' : 'w'; - } - - return (int)adodb_date($mapping[$field_type], $date); - } - - /** - * Test if a value is within a range - * - * @param string $date_value Set date value - * @param string $rule Value to test - * @return bool - * @access protected - */ - protected function _isInRange($date_value, $rule) - { - $parts = array_map('trim', explode('-', $rule, 2)); - - return $date_value >= $parts[0] && $date_value <= $parts[1]; - } - - /** - * Test if a value is within an increments of ranges (offset[-to]/step size) - * - * @param string $date_value Set date value - * @param string $rule Value to test - * @return bool - * @access protected - */ - protected function _isInIncrement($date_value, $rule) - { - $parts = array_map('trim', explode('/', $rule, 2)); - $stepSize = isset($parts[1]) ? $parts[1] : 0; - - if ( $parts[0] == '*' || $parts[0] == 0 ) { - return (int)$date_value % $stepSize == 0; - } - - $range = explode('-', $parts[0], 2); - $offset = $range[0]; - $to = isset($range[1]) ? $range[1] : $date_value; - - // Ensure that the date value is within the range - if ( $date_value < $offset || $date_value > $to ) { - return false; - } - - for ($i = $offset; $i <= $to; $i += $stepSize) { - if ( $i == $date_value ) { - return true; - } - } - - return false; - } - - /** - * Increments/decrements given date for 1 unit based on field type - * - * @param int $field_type - * @param int $date - * @param bool $inverse - * @return int - * @access public - */ - public function increment($field_type, $date, $inverse = false) - { - $mapping = Array ( - kCronHelper::MINUTE => '1 minute', - kCronHelper::HOUR => '1 hour', - kCronHelper::DAY => '1 day', - kCronHelper::MONTH => '1 month', - kCronHelper::WEEKDAY => '1 day', - ); - - return $this->_resetTime($field_type, strtotime(($inverse ? '-' : '+') . $mapping[$field_type], $date), $inverse); - } - - /** - * Resets time based on field type - * - * @param int $field_type - * @param int $date - * @param bool $inverse - * @return int - * @access public - */ - protected function _resetTime($field_type, $date, $inverse = false) - { - if ( $field_type == kCronHelper::MONTH || $field_type == kCronHelper::WEEKDAY || $field_type == kCronHelper::DAY ) { - if ( $inverse ) { - $date = strtotime(adodb_date('Y-m-d 23:59:59', $date)); - // set time 23:59:00 - } - else { - // set time 00:00:00 - $date = strtotime(adodb_date('Y-m-d 00:00:00', $date)); - } - } - elseif ( $field_type == kCronHelper::HOUR ) { - if ( $inverse ) { - // set time :59:00 - $date = strtotime(adodb_date('Y-m-d H:59:59', $date)); - } - else { - // set time :00:00 - $date = strtotime(adodb_date('Y-m-d H:00:00', $date)); - } - } - - return $date; - } -} \ No newline at end of file +}