Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
recurrence.php
1<?php
2
4
7use Bitrix\Calendar\Core;
9use DateTime;
10use Exception;
11
13{
14 public const PERIOD_TYPES = [
15 'WEEKLY' => 'WEEKLY',
16 'HOURLY' => 'HOURLY',
17 'DAILY' => 'DAILY',
18 'MONTHLY' => 'MONTHLY',
19 'YEARLY' => 'YEARLY',
20 ];
21
22 private const UNIT_MAP = [
23 'WEEKLY' => 'week',
24 // 'HOURLY' => 'hour',
25 'DAILY' => 'day',
26 'MONTHLY' => 'month',
27 'YEARLY' => 'year',
28 ];
29
30 private const WEEK_DAYS_SHORT = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
31
32 private const WEEK_DAYS = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
33
47 public function getEventOccurenceDates(Event $event, array $params = []): array
48 {
49 $limits = $this->prepareLimits($event, $params);
50
51 $result = [];
52 $counter = 0;
53
54 $pushToResult = function (DateTime $date) use (&$result, &$counter)
55 {
56 $result[$date->format('d.m.Y')] = $date;
57 $counter++;
58 };
59
60 $start = clone $event->getStart();
61 $start->resetTime();
62 $date = $this->convertBitrixDateToPhpDate($start);
63
64 while ($this->isDateWithinLimits($date, $limits, $counter))
65 {
66 if ($event->getRecurringRule()->getFrequency() === self::PERIOD_TYPES['WEEKLY'])
67 {
68 if (empty($started))
69 {
70 $started = true;
71 // return array like [0, 2, 5] for sunday, tuesday, friday
72 $weekDays = $weekDays ?? $this->prepareWeekDays($event->getRecurringRule()->getByday());
73 $weekDay = (int)$date->format('w');
74 if (!in_array($weekDay, $weekDays))
75 {
76 $this->moveToNextWeekDay($date, $weekDays);
77 }
78 }
79 else
80 {
81 $pushToResult(clone $date);
82 $this->moveToNextWeekDay($date, $weekDays);
83 }
84 }
85 else
86 {
87 $pushToResult(clone $date);
88 $unit = self::UNIT_MAP[$event->getRecurringRule()->getFrequency()] ?? null;
89 if ($unit === null)
90 {
91 throw new BaseException(
92 "Unsupported frequency type: " . $event->getRecurringRule()->getFrequency(),
93 406,
94 __FILE__,
95 __LINE__
96 );
97 }
98
99 $date->modify('+' . $event->getRecurringRule()->getInterval() . ' ' . $unit);
100 }
101 }
102
103 $this->removeExcludedDates($event, $result);
104
105 return $result;
106 }
107
113 private function prepareWeekDays(array $getByday): array
114 {
115 $days = array_flip(self::WEEK_DAYS_SHORT);
116 return array_map(function ($val) use ($days) {
117 return $days[$val];
118 }, $getByday);
119 }
120
127 private function moveToNextWeekDay(DateTime $date, array $weekDays): void
128 {
129 $current = (int)$date->format('w');
130 foreach ($weekDays as $weekDay)
131 {
132 if ($weekDay > $current)
133 {
134 $nextDay = $weekDay;
135 break;
136 }
137 }
138 $nextDayIndex = $nextDay ?? reset($weekDays);
139 $nextDayName = self::WEEK_DAYS[$nextDayIndex];
140 $date->modify("next $nextDayName");
141 }
142
150 private function prepareLimits(Event $event, array $params): array
151 {
152 $getCount = static function (Event $event, array $params)
153 {
154 return $params['limitCount']
155 ?? $event->getRecurringRule()
156 ? $event->getRecurringRule()->getCount()
157 : null
158 ;
159 };
160
161 $getFrom = function (Event $event, array $params)
162 {
163 if (!empty($params['limitDateFrom']))
164 {
165 return max(
166 $this->convertBitrixDateToPhpDate($params['limitDateFrom']),
167 $this->convertBitrixDateToPhpDate($event->getStart())
168 );
169 }
170 else
171 {
172 return $this->convertBitrixDateToPhpDate($event->getStart());
173 }
174 };
175
176 $getTo = function (Event $event, array $params)
177 {
178 $until = (!is_null($event->getRecurringRule()) && $event->getRecurringRule()->hasUntil())
179 ? $this->convertBitrixDateToPhpDate($event->getRecurringRule()->getUntil())
180 : null;
181 if (empty($params['limitDateTo']))
182 {
183 return $until;
184 }
185 elseif ($until)
186 {
187 return min(
188 $this->convertBitrixDateToPhpDate($params['limitDateTo']),
189 $until
190 );
191 }
192 else
193 {
194 return $params['limitDateTo'];
195 }
196 };
197
198 return [
199 'count' => $getCount($event, $params),
200 'from' => $getFrom($event, $params),
201 'to' => $getTo($event, $params),
202 ];
203 }
204
211 private function convertBitrixDateToPhpDate($date): DateTime
212 {
213 return new DateTime($date->format('c'));
214 }
215
223 private function isDateWithinLimits(DateTime $date, array $limits, int $counter): bool
224 {
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'))
228 ;
229 }
230
237 private function removeExcludedDates(Event $event, array &$result): void
238 {
239 if ($event->getExcludedDateCollection() && $event->getExcludedDateCollection()->count())
240 {
242 foreach ($event->getExcludedDateCollection() as $excludedDate)
243 {
244 $key = $excludedDate->format('d.m.Y');
245 if (array_key_exists($key, $result))
246 {
247 unset($result[$key]);
248 }
249 }
250 }
251 }
252}
getEventOccurenceDates(Event $event, array $params=[])