18 'MONTHLY' =>
'MONTHLY',
22 private const UNIT_MAP = [
30 private const WEEK_DAYS_SHORT = [
'SU',
'MO',
'TU',
'WE',
'TH',
'FR',
'SA'];
32 private const WEEK_DAYS = [
'sunday',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday'];
49 $limits = $this->prepareLimits($event, $params);
54 $pushToResult =
function (DateTime $date) use (&$result, &$counter)
56 $result[$date->format(
'd.m.Y')] = $date;
62 $date = $this->convertBitrixDateToPhpDate($start);
64 while ($this->isDateWithinLimits($date, $limits, $counter))
66 if ($event->
getRecurringRule()->getFrequency() === self::PERIOD_TYPES[
'WEEKLY'])
72 $weekDays = $weekDays ?? $this->prepareWeekDays($event->
getRecurringRule()->getByday());
73 $weekDay = (int)$date->format(
'w');
74 if (!in_array($weekDay, $weekDays))
76 $this->moveToNextWeekDay($date, $weekDays);
81 $pushToResult(clone $date);
82 $this->moveToNextWeekDay($date, $weekDays);
87 $pushToResult(clone $date);
99 $date->modify(
'+' . $event->
getRecurringRule()->getInterval() .
' ' . $unit);
103 $this->removeExcludedDates($event, $result);
113 private function prepareWeekDays(array $getByday): array
115 $days = array_flip(self::WEEK_DAYS_SHORT);
116 return array_map(
function ($val) use ($days) {
127 private function moveToNextWeekDay(
DateTime $date, array $weekDays): void
129 $current = (int)$date->
format(
'w');
130 foreach ($weekDays as $weekDay)
132 if ($weekDay > $current)
138 $nextDayIndex = $nextDay ?? reset($weekDays);
139 $nextDayName = self::WEEK_DAYS[$nextDayIndex];
140 $date->modify(
"next $nextDayName");
150 private function prepareLimits(Event $event, array $params): array
152 $getCount =
static function (Event $event, array $params)
154 return $params[
'limitCount']
155 ?? $event->getRecurringRule()
156 ? $event->getRecurringRule()->getCount()
161 $getFrom =
function (Event $event, array $params)
163 if (!empty($params[
'limitDateFrom']))
166 $this->convertBitrixDateToPhpDate($params[
'limitDateFrom']),
167 $this->convertBitrixDateToPhpDate($event->getStart())
172 return $this->convertBitrixDateToPhpDate($event->getStart());
176 $getTo =
function (Event $event, array $params)
178 $until = (!is_null($event->getRecurringRule()) && $event->getRecurringRule()->hasUntil())
179 ? $this->convertBitrixDateToPhpDate($event->getRecurringRule()->getUntil())
181 if (empty($params[
'limitDateTo']))
188 $this->convertBitrixDateToPhpDate($params[
'limitDateTo']),
194 return $params[
'limitDateTo'];
199 'count' => $getCount($event, $params),
200 'from' => $getFrom($event, $params),
201 'to' => $getTo($event, $params),
211 private function convertBitrixDateToPhpDate($date): DateTime
213 return new DateTime($date->
format(
'c'));
223 private function isDateWithinLimits(DateTime $date, array $limits,
int $counter): bool
225 return (empty($limits[
'count']) || $counter < $limits[
'count'])
226 && ($date->format(
'Ymd') >= $limits[
'from']->format(
'Ymd'))
227 && (empty($limits[
'to']) || $date->format(
'Ymd') <= $limits[
'to']->format(
'Ymd'))
237 private function removeExcludedDates(Event $event, array &$result): void
239 if ($event->getExcludedDateCollection() && $event->getExcludedDateCollection()->count())
242 foreach ($event->getExcludedDateCollection() as $excludedDate)
244 $key = $excludedDate->format(
'd.m.Y');
245 if (array_key_exists($key, $result))
247 unset($result[$key]);