ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
BuilderImpl.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
23 use ilLanguage;
30 use ilCalendarUtil;
32 use ilDate;
33 use DateTimeZone;
38 
39 class 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()
148  ])->withAdditionalTransformation($this->getOutputTransformation());
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();
166  $groups[self::MONTHLY_BY_DATE] = $this->getMonthlyByDateGroup();
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()) {
174  ilCalendarRecurrence::FREQ_DAILY => self::DAILY,
175  ilCalendarRecurrence::FREQ_WEEKLY => self::WEEKLY,
176  ilCalendarRecurrence::FREQ_MONTHLY => $this->recurrence->getBYDAY() ? self::MONTHLY_BY_DAY : self::MONTHLY_BY_DATE,
177  ilCalendarRecurrence::FREQ_YEARLY => $this->recurrence->getBYDAY() ? self::YEARLY_BY_DAY : self::YEARLY_BY_DATE,
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 
466  case self::MONTHLY_BY_DAY:
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 
475  case self::MONTHLY_BY_DATE:
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 
481  case self::YEARLY_BY_DAY:
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 
491  case self::YEARLY_BY_DATE:
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:
499  case self::NO_RECURRENCE:
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 }
static _numericMonthToString(int $a_month, bool $a_long=true, ?ilLanguage $lng=null)
numeric month to string
const IL_CAL_UNIX
static _numericDayToString(int $a_day, bool $a_long=true, ?ilLanguage $lng=null)
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:61
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:26
global $lng
Definition: privfeed.php:31
A transformation is a function from one datatype to another.
This describes commonalities between all inputs.
Definition: Input.php:46
__construct(protected ilCalendarRecurrence $recurrence, protected UIFactory $ui_factory, protected Refinery $refinery, protected ilLanguage $lng, protected ilCalendarUserSettings $user_settings)
Definition: BuilderImpl.php:75