ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
BuilderImpl.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use ilLanguage;
24use ILIAS\UI\Factory as UIFactory;
27use ILIAS\Refinery\Factory as Refinery;
32use ilDate;
33use DateTimeZone;
37use DateTimeImmutable;
38
39class BuilderImpl implements Builder
40{
41 // radios
42 protected const string RULE = 'rule';
43 protected const string END = 'end';
44
45 //rule freq
46 protected const string NO_RECURRENCE = 'none';
47 protected const string DAILY = 'daily';
48 protected const string WEEKLY = 'weekly';
49 protected const string MONTHLY_BY_DAY = 'monthly_by_day';
50 protected const string MONTHLY_BY_DATE = 'monthly_by_date';
51 protected const string YEARLY_BY_DAY = 'yearly_by_day';
52 protected const string YEARLY_BY_DATE = 'yearly_by_date';
53
54 // common rule inputs
55 protected const string INTERVAL = 'interval';
56 protected const string MONTH = 'month';
57 protected const string WEEK = 'week';
58 protected const string DAY = 'day';
59 protected const string DAY_OF_MONTH = 'day_of_month';
60
61
62 // end inputs
63 protected const string NO_UNTIL = 'no_until';
64 protected const string COUNT = 'count';
65 protected const string UNTIL_COUNT = 'until_count';
66 protected const string END_DATE = 'end_date';
67 protected const string UNTIL_END_DATE = 'until_end_date';
68
69 protected bool $unlimited_recurrences = true;
70 protected bool $daily = true;
71 protected bool $weekly = true;
72 protected bool $monthly = true;
73 protected bool $yearly = true;
74
75 public function __construct(
76 protected ilCalendarRecurrence $recurrence,
77 protected UIFactory $ui_factory,
78 protected Refinery $refinery,
79 protected ilLanguage $lng,
80 protected ilCalendarUserSettings $user_settings
81 ) {
82 }
83
84 public function withoutUnlimitedRecurrences(bool $without = true): Builder
85 {
86 $clone = clone $this;
87 $clone->unlimited_recurrences = !$without;
88 return $clone;
89 }
90
91 public function withoutDaily(bool $without = true): Builder
92 {
93 $clone = clone $this;
94 $clone->daily = !$without;
95 return $clone;
96 }
97
98 public function withoutWeekly(bool $without = true): Builder
99 {
100 $clone = clone $this;
101 $clone->weekly = !$without;
102 return $clone;
103 }
104
105 public function withoutMonthly(bool $without = true): Builder
106 {
107 $clone = clone $this;
108 $clone->monthly = !$without;
109 return $clone;
110 }
111
112 public function withoutYearly(bool $without = true): Builder
113 {
114 $clone = clone $this;
115 $clone->yearly = !$without;
116 return $clone;
117 }
118
119 public function hasUnlimitedRecurrences(): bool
120 {
122 }
123
124 public function hasDaily(): bool
125 {
126 return $this->daily;
127 }
128
129 public function hasWeekly(): bool
130 {
131 return $this->weekly;
132 }
133
134 public function hasMonthly(): bool
135 {
136 return $this->monthly;
137 }
138
139 public function hasYearly(): bool
140 {
141 return $this->yearly;
142 }
143
144 public function get(): Group
145 {
146 return $this->ui_factory->input()->field()->group([
147 self::RULE => $this->getRuleInput()
149 }
150
151 protected function getRuleInput(): Input
152 {
153 $groups = [];
154 $groups[self::NO_RECURRENCE] = $this->ui_factory->input()->field()->group(
155 [],
156 $this->lng->txt('cal_no_recurrence')
157 );
158 if ($this->hasDaily()) {
159 $groups[self::DAILY] = $this->getDailyGroup();
160 }
161 if ($this->hasWeekly()) {
162 $groups[self::WEEKLY] = $this->getWeeklyGroup();
163 }
164 if ($this->hasMonthly()) {
165 $groups[self::MONTHLY_BY_DAY] = $this->getMonthlyByDayGroup();
167 }
168 if ($this->hasYearly()) {
169 $groups[self::YEARLY_BY_DAY] = $this->getYearlyByDayGroup();
170 $groups[self::YEARLY_BY_DATE] = $this->getYearlyByDateGroup();
171 }
172
173 $value = match ($this->recurrence->getFrequenceType()) {
178 default => self::NO_RECURRENCE
179 };
180 return $this->ui_factory->input()->field()->switchableGroup(
181 $groups,
182 $this->lng->txt('cal_recurrences')
183 )->withValue($value);
184 }
185
186 protected function getDailyGroup(): Group
187 {
188 return $this->ui_factory->input()->field()->group(
189 [
190 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_day_interval')),
191 self::END => $this->getEndInput()
192 ],
193 $this->lng->txt('cal_daily')
194 );
195 }
196
197 protected function getWeeklyGroup(): Group
198 {
199 return $this->ui_factory->input()->field()->group(
200 [
201 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_week_interval')),
202 self::DAY => $this->getDayInput(),
203 self::END => $this->getEndInput()
204 ],
205 $this->lng->txt('cal_weekly')
206 );
207 }
208
209 protected function getMonthlyByDayGroup(): Group
210 {
211 return $this->ui_factory->input()->field()->group(
212 [
213 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_month_interval')),
214 self::WEEK => $this->getWeekInput(),
215 self::DAY => $this->getDayInput(),
216 self::END => $this->getEndInput()
217 ],
218 $this->lng->txt('cal_monthly_by_day')
219 );
220 }
221
222 protected function getMonthlyByDateGroup(): Group
223 {
224 return $this->ui_factory->input()->field()->group(
225 [
226 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_month_interval')),
227 self::DAY_OF_MONTH => $this->getDayOfMonthInput(),
228 self::END => $this->getEndInput()
229 ],
230 $this->lng->txt('cal_monthly_by_date')
231 );
232 }
233
234 protected function getYearlyByDayGroup(): Group
235 {
236 return $this->ui_factory->input()->field()->group(
237 [
238 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_year_interval')),
239 self::MONTH => $this->getMonthInput(),
240 self::WEEK => $this->getWeekInput(),
241 self::DAY => $this->getDayInput(),
242 self::END => $this->getEndInput()
243 ],
244 $this->lng->txt('cal_yearly_by_day')
245 );
246 }
247
248 protected function getYearlyByDateGroup(): Group
249 {
250 return $this->ui_factory->input()->field()->group(
251 [
252 self::INTERVAL => $this->getIntervalInput($this->lng->txt('cal_recurrence_year_interval')),
253 self::MONTH => $this->getMonthInput(),
254 self::DAY_OF_MONTH => $this->getDayOfMonthInput(),
255 self::END => $this->getEndInput()
256 ],
257 $this->lng->txt('cal_yearly_by_date')
258 );
259 }
260
261 protected function getEndInput(): Input
262 {
263 $groups = [];
264
265 if ($this->unlimited_recurrences) {
266 $groups[self::NO_UNTIL] = $this->ui_factory->input()->field()->group(
267 [],
268 $this->lng->txt('cal_no_ending')
269 );
270 }
271
272 $count_value = $this->recurrence->getFrequenceUntilCount();
273 if ($count_value < 1 || $count_value > 100) {
274 $count_value = 1;
275 }
276 $count = $this->ui_factory->input()->field()->numeric($this->lng->txt('cal_recurrence_count'))
277 ->withValue($count_value)
278 ->withRequired(true)
279 ->withAdditionalTransformation(
280 $this->refinery->in()->series([
281 $this->refinery->int()->isGreaterThanOrEqual(1),
282 $this->refinery->int()->isLessThanOrEqual(100),
283 ])
284 );
285 $groups[self::UNTIL_COUNT] = $this->ui_factory->input()->field()->group(
286 [self::COUNT => $count],
287 $this->lng->txt('cal_recurrence_until_count')
288 );
289
290 $end_date = $this->ui_factory->input()->field()->dateTime(
291 $this->lng->txt('cal_recurrence_end_date'),
292 $this->lng->txt('cal_recurrence_end_date_info')
293 )->withTimezone('UTC')
294 ->withUseTime(false)
295 ->withRequired(true);
296 if ($this->recurrence->getFrequenceUntilDate()) {
297 $end_date = $end_date->withValue(
298 new DateTimeImmutable('@' . $this->recurrence->getFrequenceUntilDate()->getUnixTime())
299 );
300 }
301 $groups[self::UNTIL_END_DATE] = $this->ui_factory->input()->field()->group(
302 [self::END_DATE => $end_date],
303 $this->lng->txt('cal_recurrence_until_end_date')
304 );
305
306 $value = self::NO_UNTIL;
307 if ($this->recurrence->getFrequenceUntilDate()) {
308 $value = self::UNTIL_END_DATE;
309 }
310 if ($this->recurrence->getFrequenceUntilCount()) {
311 $value = self::UNTIL_COUNT;
312 }
313 return $this->ui_factory->input()->field()->switchableGroup(
314 $groups,
315 $this->lng->txt('cal_recurrence_until')
316 )->withValue($value);
317 }
318
319 protected function getIntervalInput(string $label): Input
320 {
321 return $this->ui_factory->input()->field()->numeric($label)
322 ->withValue($this->recurrence->getInterval())
323 ->withRequired(true)
324 ->withAdditionalTransformation(
325 $this->refinery->int()->isGreaterThanOrEqual(1)
326 );
327 }
328
329 protected function getDayInput(): Input
330 {
331 $days = [
332 0 => Weekday::SUNDAY->value,
333 1 => Weekday::MONDAY->value,
334 2 => Weekday::TUESDAY->value,
335 3 => Weekday::WEDNESDAY->value,
336 4 => Weekday::THURSDAY->value,
337 5 => Weekday::FRIDAY->value,
338 6 => Weekday::SATURDAY->value,
339 7 => Weekday::SUNDAY->value
340 ];
341 $options = [];
342 for ($i = $this->user_settings->getWeekStart(); $i < 7 + $this->user_settings->getWeekStart(); $i++) {
343 $options[$days[$i]] = ilCalendarUtil::_numericDayToString($i);
344 }
345
346 $values = [];
347 foreach ($this->recurrence->getBYDAYList() as $byday) {
348 // BYDAY can also contain ordinance numbers in front of the days
349 $v = substr($byday, -2);
350 if (in_array($v, $days)) {
351 $values[] = $v;
352 }
353 }
354
355 return $this->ui_factory->input()->field()->multiSelect(
356 $this->lng->txt('cal_day_s'),
357 $options
358 )->withValue($values)->withRequired(true);
359 }
360
361 protected function getWeekInput(): Input
362 {
363 $options = [
364 Ordinal::FIRST->value => $this->lng->txt('cal_first'),
365 Ordinal::SECOND->value => $this->lng->txt('cal_second'),
366 Ordinal::THIRD->value => $this->lng->txt('cal_third'),
367 Ordinal::FOURTH->value => $this->lng->txt('cal_fourth'),
368 Ordinal::FIFTH->value => $this->lng->txt('cal_fifth'),
369 Ordinal::LAST->value => $this->lng->txt('cal_last')
370 ];
371
372 // The last two characters of any BYDAY entry are the day, the remainder is the ordinal.
373 $value = substr($this->recurrence->getBYDAYList()[0] ?? '', 0, -2);
374 if ($value === '') {
375 $value = Ordinal::FIRST->value;
376 }
377
378 return $this->ui_factory->input()->field()->select(
379 $this->lng->txt('week'),
380 $options
381 )->withValue($value)->withRequired(true);
382 }
383
384 protected function getDayOfMonthInput(): Input
385 {
386 $value = (int) $this->recurrence->getBYMONTHDAY();
387 if ($value < 1 || $value > 31) {
388 $value = 1;
389 }
390 return $this->ui_factory->input()->field()->numeric($this->lng->txt('cal_day_of_month'))
391 ->withValue($value)
392 ->withRequired(true)
393 ->withAdditionalTransformation(
394 $this->refinery->in()->series([
395 $this->refinery->int()->isGreaterThanOrEqual(1),
396 $this->refinery->int()->isLessThanOrEqual(31),
397 ])
398 );
399 }
400
401 protected function getMonthInput(): Input
402 {
403 $months = [
404 1 => Month::JANUARY->value,
405 2 => Month::FEBRUARY->value,
406 3 => Month::MARCH->value,
407 4 => Month::APRIL->value,
408 5 => Month::MAY->value,
409 6 => Month::JUNE->value,
410 7 => Month::JULY->value,
411 8 => Month::AUGUST->value,
412 9 => Month::SEPTEMBER->value,
413 10 => Month::OCTOBER->value,
414 11 => Month::NOVEMBER->value,
415 12 => Month::DECEMBER->value
416 ];
417 $options = [];
418 foreach ($months as $month => $key) {
419 $options[$key] = ilCalendarUtil::_numericMonthToString($month);
420 }
421
422 $value = $this->recurrence->getBYMONTH();
423 if (!in_array($value, $options)) {
424 $value = Month::JANUARY->value;
425 }
426 return $this->ui_factory->input()->field()->select(
427 $this->lng->txt('month'),
428 $options
429 )->withValue($value)->withRequired(true);
430 }
431
433 {
434 $recurrence = clone $this->recurrence;
435 $with_daily = $this->hasDaily();
436 $with_weekly = $this->hasWeekly();
437 $with_monthly = $this->hasMonthly();
438 $with_yearly = $this->hasYearly();
439 $with_unlimited = $this->hasUnlimitedRecurrences();
440
441 return $this->refinery->custom()->transformation(function ($values) use (
442 $recurrence,
443 $with_daily,
444 $with_weekly,
445 $with_monthly,
446 $with_yearly,
447 $with_unlimited
448 ) {
449 $recurrence->reset();
450
451 $rule_data = $values[self::RULE];
452 switch ($rule_data[0]) {
453 case self::DAILY:
454 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_DAILY);
455 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
456 break;
457
458 case self::WEEKLY:
459 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_WEEKLY);
460 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
461 if (is_array($rule_data[1][self::DAY]) && $rule_data[1][self::DAY] !== []) {
462 $recurrence->setBYDAY(implode(',', $rule_data[1][self::DAY]));
463 }
464 break;
465
467 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_MONTHLY);
468 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
469 if (is_array($rule_data[1][self::DAY]) && $rule_data[1][self::DAY] !== []) {
470 $index = $rule_data[1][self::WEEK];
471 $recurrence->setBYDAY($index . implode(',' . $index, $rule_data[1][self::DAY]));
472 }
473 break;
474
476 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_MONTHLY);
477 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
478 $recurrence->setBYMONTHDAY((string) $rule_data[1][self::DAY_OF_MONTH]);
479 break;
480
482 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_YEARLY);
483 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
484 $recurrence->setBYMONTH((string) $rule_data[1][self::MONTH]);
485 if (is_array($rule_data[1][self::DAY]) && $rule_data[1][self::DAY] !== []) {
486 $index = $rule_data[1][self::WEEK];
487 $recurrence->setBYDAY($index . implode(',' . $index, $rule_data[1][self::DAY]));
488 }
489 break;
490
492 $recurrence->setFrequenceType(ilCalendarRecurrence::FREQ_YEARLY);
493 $recurrence->setInterval((int) $rule_data[1][self::INTERVAL]);
494 $recurrence->setBYMONTH((string) $rule_data[1][self::MONTH]);
495 $recurrence->setBYMONTHDAY((string) $rule_data[1][self::DAY_OF_MONTH]);
496 break;
497
498 default:
500 break;
501 }
502
503 $end_data = $rule_data[1][self::END];
504 if ($end_data[0] === self::UNTIL_COUNT) {
505 $recurrence->setFrequenceUntilCount($end_data[1][self::COUNT]);
506 }
507 if ($end_data[0] === self::UNTIL_END_DATE) {
508 $recurrence->setFrequenceUntilDate(new ilDate(
509 $end_data[1][self::END_DATE]->getTimestamp(),
511 ));
512 }
513
514 return $recurrence;
515 });
516 }
517}
__construct(protected ilCalendarRecurrence $recurrence, protected UIFactory $ui_factory, protected Refinery $refinery, protected ilLanguage $lng, protected ilCalendarUserSettings $user_settings)
Definition: BuilderImpl.php:75
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
const IL_CAL_UNIX
Model of calendar entry recurrcences based on iCalendar-RFC-5545.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _numericDayToString(int $a_day, bool $a_long=true, ?ilLanguage $lng=null)
static _numericMonthToString(int $a_month, bool $a_long=true, ?ilLanguage $lng=null)
numeric month to string
Class for single dates.
language handling
A transformation is a function from one datatype to another.
Describes the monoid operation of grouping form inputs.
Definition: Group.php:32
This describes commonalities between all inputs.
Definition: Input.php:47
withValue($value)
Get an input like this with another value displayed on the client side.
Ordinal
Technically these also include the sign...
Definition: Ordinal.php:27
withAdditionalTransformation(Transformation $trafo)
@inheritDoc
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:61
global $lng
Definition: privfeed.php:31