Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
/**
* ResourceRequest.class.php - Contains a model class for resource requests.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* @author Moritz Strohm <strohm@data-quest.de>
* @copyright 2017-2019
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
* @package resources
* @since 4.5
*/
/**
* ResourceRequest is a model class for resource requests.
*
* @property string id database column
* @property string resource_id database column
* @property string category_id database column
* @property string course_id database column
* @property string termin_id database column
* @property string metadate_id database column
* @property string begin database column
* @property string end database column
* @property string preparation_time databasse column
* @property string marked database column
* There are four marking states:
* 0 - not marked
* 1 - red state
* 2 - yellow state
* 3 - green state
* @property string user_id database column
* @property string last_modified_by database column
* @property string comment database column
* @property string reply_comment database column
* @property string reply_recipients database column:
* enum('requester', 'lecturer')
* @property string closed database column, possible states are:
* 0 - room-request is open
* 1 - room-request has been processed, but no confirmation has been sent
* 2 - room-request has been processed and a confirmation has been sent
* 3 - room-request has been declined
*
* @property string mkdate database column
* @property string chdate database column
* @property Resource resource belongs_to Resource
* @property User requester belongs_to User
* @property User last_modifier belongs_to User
*
*
* The attributes begin and end are only used in simple resource requests.
* The "traditional" resource requests use either course_id, metadate_id
* or termin_id to store the time ranges connected to the request.
*/
class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calendar\EventSource
{
/**
* The amount of defined marking states.
*/
const MARKING_STATES = 4;
protected static function configure($config = [])
{
$config['db_table'] = 'resource_requests';
$config['belongs_to']['resource'] = [
'class_name' => Resource::class,
'foreign_key' => 'resource_id',
'assoc_func' => 'find'
];
$config['belongs_to']['category'] = [
'class_name' => ResourceCategory::class,
'foreign_key' => 'category_id',
'assoc_func' => 'find'
];
$config['belongs_to']['user'] = [
'class_name' => User::class,
'foreign_key' => 'user_id',
'assoc_func' => 'find'
];
$config['belongs_to']['last_modifier'] = [
'class_name' => User::class,
'foreign_key' => 'last_modified_by',
'assoc_func' => 'find'
];
$config['belongs_to']['course'] = [
'class_name' => Course::class,
'foreign_key' => 'course_id',
'assoc_func' => 'find'
];
$config['belongs_to']['cycle'] = [
'class_name' => SeminarCycleDate::class,
'foreign_key' => 'metadate_id'
];
$config['belongs_to']['date'] = [
'class_name' => CourseDate::class,
'foreign_key' => 'termin_id'
];
$config['has_many']['properties'] = [
'class_name' => ResourceRequestProperty::class,
'foreign_key' => 'id',
'assoc_foreign_key' => 'request_id',
'on_store' => 'store',
'on_delete' => 'delete'
];
$config['has_many']['appointments'] = [
'class_name' => ResourceRequestAppointment::class,
'foreign_key' => 'id',
'assoc_foreign_key' => 'request_id',
'on_store' => 'store',
'on_delete' => 'delete'
];
//In regard to TIC 6460:
//As long as TIC 6460 is not implemented, we must add the validate
//method as a callback before storing the object.
if (!method_exists('SimpleORMap', 'validate')) {
$config['registered_callbacks']['before_store'][] = 'validate';
}
$config['registered_callbacks']['after_create'][] = 'cbLogNewRequest';
$config['registered_callbacks']['after_store'][] = 'cbAfterStore';
$config['registered_callbacks']['after_delete'][] = 'cbAfterDelete';
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
parent::configure($config);
}
/**
* @inheritDoc
*/
public static function exportUserdata(StoredUserData $storage)
{
$user = User::find($storage->user_id);
$requests = self::findBySql(
'user_id = :user_id ORDER BY mkdate',
[
'user_id' => $storage->user_id
]
);
$request_rows = [];
foreach ($requests as $request) {
$request_rows[] = $request->toRawArray();
}
$storage->addTabularData(
_('Ressourcenanfragen'),
'resource_requests',
$request_rows,
$user
);
}
/**
* Retrieves all resource requests from the database.
*
* @return ResourceRequest[] An array of ResourceRequests objects
* or an empty array, if no resource requests are stored
* in the database.
*/
public static function findAll()
{
return self::findBySql('TRUE ORDER BY mkdate ASC');
}
/**
* Retrieves all open resource requests from the database.
*
* @return ResourceRequest[] An array of ResourceRequests objects
* or an empty array, if no open resource requests are stored
* in the database.
*/
public static function findOpen()
{
return self::findBySql("closed = '0' ORDER BY mkdate ASC");
}
/**
* Internal method that generated the SQL query used in
* findByResourceAndTimeRanges and countByResourceAndTimeRanges.
*
* @see findByResourceAndTimeRanges
* @inheritDoc
*/
protected static function buildResourceAndTimeRangesSqlQuery(
Resource $resource,
$time_ranges = [],
$closed_status = null,
$excluded_request_ids = [],
$additional_conditions = '',
$additional_parameters = []
)
{
if (!is_array($time_ranges)) {
throw new InvalidArgumentException(
_('Es wurde keine Liste mit Zeiträumen angegeben!')
);
}
//Check the array:
foreach ($time_ranges as $time_range) {
if ($time_range['begin'] > $time_range['end']) {
throw new InvalidArgumentException(
_('Der Startzeitpunkt darf nicht hinter dem Endzeitpunkt liegen!')
);
}
if ($time_range['begin'] == $time_range['end']) {
throw new InvalidArgumentException(
_('Startzeitpunkt und Endzeitpunkt dürfen nicht identisch sein!')
);
}
}
$sql_params = [
'resource_id' => $resource->id
];
//First we build the SQL snippet for the case that the $closed_status
//variable is set to something different than null.
$closed_status_sql = '';
if ($closed_status !== null) {
$closed_status_sql = ' AND (resource_requests.closed = :status) ';
$sql_params['status'] = strval($closed_status);
}
//Then we build the snipped for excluded request IDs, if specified.
$excluded_request_ids_sql = '';
if (is_array($excluded_request_ids) && count($excluded_request_ids)) {
$excluded_request_ids_sql = ' AND resource_requests.id NOT IN ( :excluded_ids ) ';
$sql_params['excluded_ids'] = $excluded_request_ids;
}
//Now we build the SQL snippet for the time intervals.
//These are repeated four times in the query below.
//BEGIN and END are replaced below since the columns for
//BEGIN and END are different in the four cases where we
//repeat the SQL snippet for the time intervals.
$time_sql = '';
if ($time_ranges) {
$time_sql = 'AND (';
$i = 1;
foreach ($time_ranges as $time_range) {
if ($i > 1) {
$time_sql .= ' OR ';
}
$time_sql .= sprintf('BEGIN < :end%d AND END > :begin%d ', $i, $i);
$sql_params[('begin' . $i)] = $time_range['begin'];
$sql_params[('end' . $i)] = $time_range['end'];
$i++;
}
$time_sql .= ') ';
}
//Check if the request has a start and end timestamp set or if it belongs
//to a date, a metadate or a course.
//This is done in the rest of the SQL query:
// FIXME this subselect looks unnecessarily complex
SELECT id FROM resource_requests
WHERE
resource_id = :resource_id
'
. str_replace(
['BEGIN', 'END'],
['(CAST(begin AS SIGNED) - preparation_time)', 'end'],
$time_sql
)
. $closed_status_sql
. '
UNION
SELECT id FROM resource_requests
INNER JOIN termine USING (termin_id)
WHERE
resource_id = :resource_id
'
. str_replace(
['BEGIN', 'END'],
[
Moritz Strohm
committed
'(CAST(termine.date AS SIGNED) - resource_requests.preparation_time)',
'termine.end_time'
],
$time_sql
)
. $closed_status_sql
. '
UNION
SELECT id FROM resource_requests
INNER JOIN termine USING (metadate_id)
WHERE
resource_id = :resource_id
'
. str_replace(
['BEGIN', 'END'],
[
Moritz Strohm
committed
'(CAST(termine.date AS SIGNED) - resource_requests.preparation_time)',
'termine.end_time'
],
$time_sql
)
. $closed_status_sql
. '
UNION
SELECT id FROM resource_requests
INNER JOIN termine
ON resource_requests.course_id = termine.range_id
WHERE
resource_id = :resource_id
'
. str_replace(
['BEGIN', 'END'],
[
Moritz Strohm
committed
'(CAST(termine.date AS SIGNED) - resource_requests.preparation_time)',
'termine.end_time'
],
$time_sql
)
. $closed_status_sql
. '
$request_ids = DBManager::get()->fetchFirst($whole_sql, $sql_params);
$whole_sql = "resource_requests.id IN(:request_ids)";
$sql_params = ['request_ids' => $request_ids];
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
if ($additional_conditions) {
$whole_sql .= ' AND ' . $additional_conditions;
if ($additional_parameters) {
$sql_params = array_merge($sql_params, $additional_parameters);
}
}
$whole_sql .= ' ORDER BY mkdate ASC';
return [
'sql' => $whole_sql,
'params' => $sql_params
];
}
/**
* Retrieves all resource requests for the given resource and
* time range. By default, all requests are returned.
* To get only open or closed requests set the $closed_status parameter.
*
* @param Resource $resource The resource whose requests shall be retrieved.
* @param array $time_ranges An array with time ranges as DateTime objects.
* The array has the following structure:
* [
* [
* 'begin' => begin timestamp,
* 'end' => end timestamp
* ],
* ...
* ]
* @param mixed $closed_status An optional status for the closed column in the
* database. By default this is set to null which means that
* resource requests are not filtered by the status column field.
* A value of 0 means only open requests are retrived.
* A value of 1 means only closed requests are retrieved.
*
* @param array $excluded_request_ids An array of strings representing
* resource request IDs. IDs specified in this array are excluded from
* the search.
* @return ResourceRequest[] An array of ResourceRequest objects.
* If no requests can be found, the array is empty.
*
* @throws InvalidArgumentException, if the time ranges are either not in an
* array matching the format description from above or if one of the
* following conditions is met in one of the time ranges:
* - begin > end
* - begin == end
*/
public static function findByResourceAndTimeRanges(
Resource $resource,
$time_ranges = [],
$closed_status = null,
$excluded_request_ids = [],
$additional_conditions = '',
$additional_parameters = []
)
{
//Build the SQL query and the parameter array.
$sql_data = self::buildResourceAndTimeRangesSqlQuery(
$resource,
$time_ranges,
$closed_status,
$excluded_request_ids,
$additional_conditions,
$additional_parameters
);
//Call findBySql:
return self::findBySql($sql_data['sql'], $sql_data['params']);
}
public static function countByResourceAndTimeRanges(
Resource $resource,
$time_ranges = [],
$closed_status = null,
$excluded_request_ids = [],
$additional_conditions = '',
$additional_parameters = []
)
{
$sql_data = self::buildResourceAndTimeRangesSqlQuery(
$resource,
$time_ranges,
$closed_status,
$excluded_request_ids,
$additional_conditions,
$additional_parameters
);
return self::countBySql($sql_data['sql'], $sql_data['params']);
}
public static function findByCourse($course_id)
{
return self::findOneBySql(
"termin_id = '' AND metadate_id = '' AND course_id = :course_id",
[
'course_id' => $course_id
]
);
}
public static function findByDate($date_id)
{
return self::findOneBySql(
'termin_id = :date_id',
[
'date_id' => $date_id
]
);
}
public static function findByMetadate($metadate_id)
{
return self::findOneBySql(
'metadate_id = :metadate_id',
[
'metadate_id' => $metadate_id
]
);
}
public static function existsByCourse($course_id, $request_is_open = false)
{
$sql = '';
if ($request_is_open) {
$sql .= "closed = '0' AND ";
}
$request = self::findOneBySql(
$sql . "termin_id = '' AND metadate_id = '' AND course_id = :course_id",
[
'course_id' => $course_id
]
);
if ($request) {
return $request->id;
} else {
return false;
}
}
public static function existsByDate($date_id, $request_is_open = false)
{
$sql = '';
if ($request_is_open) {
$sql .= "closed = '0' AND ";
}
$request = self::findOneBySql(
$sql . "termin_id = :date_id",
[
'date_id' => $date_id
]
);
if ($request) {
return $request->id;
} else {
return false;
}
}
public static function existsByMetadate($metadate_id, $request_is_open = false)
{
$sql = '';
if ($request_is_open) {
$sql .= "closed = '0' AND ";
}
$request = self::findOneBySql(
$sql . "metadate_id = :metadate_id",
[
'metadate_id' => $metadate_id
]
);
if ($request) {
return $request->id;
} else {
return false;
}
}
/**
* A callback method that creates a Stud.IP log entry
* when a new request has been made.
*/
public function cbLogNewRequest()
{
$this->sendNewRequestMail();
StudipLog::log('RES_REQUEST_NEW', $this->course_id, $this->resource_id, $this->getLoggingInfoText());
}
/**
* A callback method that send a mail
* when a new request has been udpated.
*/
public function cbAfterStore()
{
if ($this->isFieldDirty('closed')) {
if ($this->closed == 3) {
$this->sendRequestDeniedMail();
StudipLog::log('RES_REQUEST_DENY', $this->course_id, $this->resource_id, $this->getLoggingInfoText());
} elseif ($this->closed == 1 || $this->closed == 2) {
StudipLog::log('RES_REQUEST_RESOLVE', $this->course_id, $this->resource_id, $this->getLoggingInfoText());
}
} else {
StudipLog::log('RES_REQUEST_UPDATE', $this->course_id, $this->resource_id, $this->getLoggingInfoText());
public function cbAfterDelete()
{
StudipLog::log('RES_REQUEST_DEL', $this->course_id, $this->resource_id, $this->getLoggingInfoText());
}
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
/**
* This validation method is called before storing an object.
*/
public function validate()
{
if (!$this->resource_id && !$this->category_id) {
throw new Exception(
_('Eine Anfrage muss einer konkreten Ressource oder deren Kategorie zugewiesen sein!')
);
}
}
public function getDerivedClassInstance()
{
if (!$this->resource) {
//We cannot determine a derived class.
return $this;
}
$class_name = $this->resource->class_name;
if ($class_name == 'Resource') {
//This is already the correct class.
return $this;
}
if (is_subclass_of($class_name, 'Resource')) {
//Now we append 'Request' to the class name:
$class_name = $class_name . 'Request';
$converted_resource = $class_name::buildExisting(
$this->toRawArray()
);
return $converted_resource;
} else {
//$class_name does not contain the name of a subclass
//of Resource. That's an error!
throw new NoResourceClassException(
sprintf(
_('Die Klasse %1$s ist keine Spezialisierung der Ressourcen-Kernklasse!'),
$class_name
)
);
}
}
/**
* Sets the range fields (termin_id, metadate_id, course_id)
* or the ResourceRequestAppointment objects related to this request
* according to the range type and its range-IDs specified as parameters
* for this method. The ResourceRequest object is not stored after
* setting the fields / related objects.
*
* @param string $range_type The range type for this request. One of
* the following: 'date', 'cycle', 'course' or 'date-multiple'.
*
* @param array $range_ids An array of range-IDs to be set for the
* specified range type. This is mostly an array of size one
* since the fields termin_id, metadate_id and course_id only
* accept one ID. The range type 'date-multiple' accepts multiple
* IDs.
*
* @return void No return value.
*/
public function setRangeFields($range_type = '', $range_ids = [])
{
if ($range_type == 'date') {
$this->termin_id = $range_ids[0];
$this->metadate_id = '';
} elseif ($range_type == 'cycle') {
$this->termin_id = '';
$this->metadate_id = $range_ids[0];
} elseif ($range_type == 'date-multiple') {
$this->termin_id = '';
$this->metadate_id = '';
$appointments = [];
foreach ($range_ids as $range_id) {
$app = new ResourceRequestAppointment();
$app->appointment_id = $range_id;
$appointments[] = $app;
}
$this->appointments = $appointments;
} elseif ($range_type == 'course') {
$this->termin_id = '';
$this->metadate_id = '';
$this->course_id = $range_ids[0];
}
}
/**
* Closes the requests and sends out notification mails.
* If the request is closed and a resource has been booked,
* it can be passed as parameter to be included in the notification mails.
*
* @param bool $notify_lecturers Whether to notify lecturers of a course
* (true) or not (false). Defaults to false. Note that this parameter
* is only useful in case the request is bound to a course, either
* directly or via a course date or a course cycle date.
*
* @param ResourceBooking $bookings The resource bookings that have been
* created from this request.
* @return bool @TODO
*/
public function closeRequest($notify_lecturers = false, $bookings = [])
{
if ($this->closed >= 2) {
//The request has already been closed.
return true;
}
$this->closed = 1;
if ($this->isDirty()) {
$this->store();
}
//Now we send the confirmation mail to the requester:
$this->sendCloseRequestMailToRequester($bookings);
if ($notify_lecturers) {
$this->sendCloseRequestMailToLecturers($bookings);
}
//Sending successful: The request is closed.
$this->closed = 2;
if ($this->isDirty()) {
return $this->store();
}
return true;
}
/**
* Returns the resource requests whose time ranges overlap
* with those of this resource request.
*
* @return ResourceRequest[] An array of ResourceRequest objects.
*/
public function getOverlappingRequests()
{
if ($this->resource) {
return self::findByResourceAndTimeRanges(
$this->resource,
$this->getTimeIntervals(true),
0,
[$this->id]
);
}
return [];
}
/**
* Counts the resource requests whose time ranges overlap
* with those of this resource request.
*
* @return int The amount of overlapping resource requests.
*/
public function countOverlappingRequests()
{
if ($this->resource) {
return self::countByResourceAndTimeRanges(
$this->resource,
$this->getTimeIntervals(true),
0,
[$this->id]
);
}
return 0;
}
/**
* Returns the resource bookings whose time ranges overlap
* with those of this resource request.
*
* @return ResourceBooking[] An array of ResourceBooking objects.
*/
public function getOverlappingBookings()
{
if ($this->resource) {
return ResourceBooking::findByResourceAndTimeRanges(
$this->resource,
$this->getTimeIntervals(true),
[0, 2]
);
}
return [];
}
/**
* Counts the resource bookings whose time ranges overlap
* with those of this resource request.
*
* @return int The amount of overlapping resource bookings.
*/
public function countOverlappingBookings()
{
if ($this->resource) {
return ResourceBooking::countByResourceAndTimeRanges(
$this->resource,
$this->getTimeIntervals(true),
[0, 2]
);
}
return 0;
}
/**
* Returns the repetion interval if regular appointments are used
* for this request.
*
* @return DateInterval|null In case regular appointments are used
* for this request a DateInterval is returned.
* Otherwise null is returned.
*/
public function getRepetitionInterval()
{
if ($this->metadate_id) {
//It is a set of regular appointments.
//We just have to compute the time difference between the first
//two appointments to get the interval.
$first_date = $this->cycle->dates[0];
$second_date = $this->cycle->dates[1];
if (!$first_date || !$second_date) {
//Either only one date is in the set of regular appointments
//or there is a database error. We cannot continue.
return null;
}
$first_datetime = new DateTime();
$first_datetime->setTimestamp($first_date->date);
$second_datetime = new DateTime();
$second_datetime->setTimestamp($second_date->date);
return $first_datetime->diff($second_datetime);
}
return null;
}
public function getStartDate()
{
$start_date = new DateTime();
if (count($this->appointments)) {
$start_date->setTimestamp($this->appointments[0]->appointment->date);
return $start_date;
} elseif ($this->termin_id) {
$start_date->setTimestamp($this->date->date);
return $start_date;
} elseif ($this->metadate_id) {
$start_date->setTimestamp($this->cycle->dates[0]->date);
return $start_date;
} elseif ($this->course_id) {
$start_date = new DateTime();
$start_date->setTimestamp($this->course->dates[0]->date);
return $start_date;
} elseif ($this->begin) {
$start_date->setTimestamp($this->begin);
return $start_date;
}
return null;
}
public function getEndDate()
{
$end_date = new DateTime();
if (count($this->appointments)) {
$end_date->setTimestamp($this->appointments->last()->appointment->end_time);
return $end_date;
} elseif ($this->termin_id) {
$end_date->setTimestamp($this->date->end_time);
return $end_date;
} elseif ($this->metadate_id) {
$end_date->setTimestamp($this->cycle->dates->last()->end_time);
return $end_date;
} elseif ($this->course_id) {
$end_date = new DateTime();
$end_date->setTimestamp($this->course->dates->last()->end_time);
return $end_date;
} elseif ($this->end) {
$end_date->setTimestamp($this->end);
return $end_date;
}
return null;
}
public function getStartSemester()
{
$start_date = $this->getStartDate();
if ($start_date instanceof DateTime) {
return Semester::findByTimestamp($start_date->getTimestamp());
}
return null;
}
public function getEndSemester()
{
$end_date = $this->getEndDate();
if ($end_date instanceof DateTime) {
return Semester::findByTimestamp($end_date->getTimestamp());
}
return null;
}
public function getRepetitionEndDate()
{
$repetition_interval = $this->getRepetitionInterval();
if (!$repetition_interval) {
//There is no repetition.
return null;
}
return $this->getEndDate();
}
/**
* Retrieves the time intervals by looking at metadate objects
* and other time interval sources and returns them grouped by metadate.
* @param bool $with_preparation_time @TODO
* @return mixed[][][] A three-dimensional array with
* the following structure:
* - The first dimension has the metadate-id as index. For single dates
* an empty string is used as index.
* - The second dimension contains two elements:
* - 'metadate' => The metadate object. This is only set, if the
* request is for a metadate.
* - 'intervals' => The time intervals.
* - The third dimension contains a time interval
* in the following format:
* [
* 'begin' => The begin timestamp
* 'end' => The end timestamp
* 'range' => The name of the range class that provides the range_id.
* This is usually the name of the SORM class.
* 'range_id' => The ID of the single date or ResourceRequestAppointment.
* ]
*/
public function getGroupedTimeIntervals($with_preparation_time = false, $with_past_intervals = true)
if (count($this->appointments)) {
$time_intervals = [
'' => [
'metadate' => null,
'intervals' => []
]
];
foreach ($this->appointments as $appointment) {
if (!$with_past_intervals && $appointment->appointment->end_time < $now) {
continue;
}
if ($with_preparation_time) {
$interval = [
'begin' => $appointment->appointment->date - $this->preparation_time,
'end' => $appointment->appointment->end_time
];
} else {
$interval = [
'begin' => $appointment->appointment->date,
'end' => $appointment->appointment->end_time
];
}
$date = CourseDate::find($appointment->appointment_id);
$interval['range'] = 'CourseDate';
$interval['range_id'] = $appointment->appointment_id;
$interval['booked_room'] = $date->room_booking->resource_id;
$interval['booking_id'] = $date->room_booking->id;
$time_intervals['']['intervals'][] = $interval;
}
if (empty($time_intervals['']['intervals'])) {
return [];
} else {
return $time_intervals;
}
} elseif ($this->termin_id) {
if (!$with_past_intervals && $this->date->end_time < $now) {
return [];
}
if ($with_preparation_time) {
$interval = [
'begin' => $this->date->date - $this->preparation_time,
'end' => $this->date->end_time
];
} else {
$interval = [
'begin' => $this->date->date,
'end' => $this->date->end_time
];
}
$date = CourseDate::find($this->termin_id);
$interval['range'] = 'CourseDate';
$interval['range_id'] = $this->termin_id;
$interval['booked_room'] = $date->room_booking->resource_id;
$interval['booking_id'] = $date->room_booking->id;
if (!empty($interval)) {
return [
'' => [
'metadate' => null,
'intervals' => [$interval]
]
];
} else {
return [];
}
} elseif ($this->metadate_id) {
$time_intervals = [
$this->metadate_id => [
'metadate' => $this->cycle,
'intervals' => []
]
];
foreach ($this->cycle->dates as $date) {
if (!$with_past_intervals && $date->end_time < $now) {
continue;
}
if ($with_preparation_time) {
$interval = [
'begin' => $date->date - $this->preparation_time,
'end' => $date->end_time
];
} else {
$interval = [
'begin' => $date->date,
'end' => $date->end_time
];
}
$interval['range'] = 'CourseDate';
$interval['range_id'] = $date->id;
$interval['booked_room'] = $date->room_booking->resource_id;
$interval['booking_id'] = $date->room_booking->id;
$time_intervals[$this->metadate_id]['intervals'][] = $interval;
}
return $time_intervals;
} elseif ($this->course_id) {
$time_intervals = [];