aboutsummaryrefslogtreecommitdiff
path: root/lib/models
diff options
context:
space:
mode:
Diffstat (limited to 'lib/models')
-rw-r--r--lib/models/AdmissionApplication.php (renamed from lib/models/AdmissionApplication.class.php)2
-rw-r--r--lib/models/ArchivedCourse.php (renamed from lib/models/ArchivedCourse.class.php)2
-rw-r--r--lib/models/ArchivedCourseMember.php (renamed from lib/models/ArchivedCourseMember.class.php)2
-rw-r--r--lib/models/AuthUserMd5.php (renamed from lib/models/AuthUserMd5.class.php)2
-rw-r--r--lib/models/AuxLockRule.php2
-rw-r--r--lib/models/Banner.php (renamed from lib/models/Banner.class.php)0
-rw-r--r--lib/models/BannerRoles.php (renamed from lib/models/BannerRoles.class.php)2
-rw-r--r--lib/models/BlubberThread.php4
-rw-r--r--lib/models/CaptchaChallenge.php88
-rw-r--r--lib/models/Clipboard.php (renamed from lib/models/Clipboard.class.php)2
-rw-r--r--lib/models/ClipboardItem.php (renamed from lib/models/ClipboardItem.class.php)34
-rw-r--r--lib/models/ColourValue.php (renamed from lib/models/ColourValue.class.php)2
-rw-r--r--lib/models/ConfigEntry.php (renamed from lib/models/ConfigEntry.class.php)2
-rw-r--r--lib/models/ConsultationBlock.php13
-rw-r--r--lib/models/ConsultationSlot.php45
-rw-r--r--lib/models/Contact.php (renamed from lib/models/Contact.class.php)2
-rw-r--r--lib/models/ContactGroup.php (renamed from lib/models/ContactGroup.class.php)0
-rw-r--r--lib/models/ContactGroupItem.php (renamed from lib/models/ContactGroupItem.class.php)0
-rw-r--r--lib/models/ContentTermsOfUse.php (renamed from lib/models/ContentTermsOfUse.class.php)2
-rw-r--r--lib/models/Course.php (renamed from lib/models/Course.class.php)24
-rw-r--r--lib/models/CourseDate.php (renamed from lib/models/CourseDate.class.php)8
-rw-r--r--lib/models/CourseExDate.php (renamed from lib/models/CourseExDate.class.php)0
-rw-r--r--lib/models/CourseMember.php (renamed from lib/models/CourseMember.class.php)2
-rw-r--r--lib/models/CourseMemberNotification.php2
-rw-r--r--lib/models/CourseTopic.php (renamed from lib/models/CourseTopic.class.php)0
-rw-r--r--lib/models/Courseware/BlockTypes/Audio.php7
-rw-r--r--lib/models/Courseware/BlockTypes/BeforeAfter.php7
-rw-r--r--lib/models/Courseware/BlockTypes/BiographyAchievements.php7
-rw-r--r--lib/models/Courseware/BlockTypes/BiographyCareer.php6
-rw-r--r--lib/models/Courseware/BlockTypes/BiographyGoals.php6
-rw-r--r--lib/models/Courseware/BlockTypes/BiographyPersonalInformation.php6
-rw-r--r--lib/models/Courseware/BlockTypes/BlockType.php13
-rw-r--r--lib/models/Courseware/BlockTypes/Canvas.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Chart.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Code.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Confirm.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Date.php6
-rw-r--r--lib/models/Courseware/BlockTypes/DialogCards.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Document.php7
-rw-r--r--lib/models/Courseware/BlockTypes/Download.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Embed.php7
-rw-r--r--lib/models/Courseware/BlockTypes/Error.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Folder.php9
-rw-r--r--lib/models/Courseware/BlockTypes/Gallery.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Headline.php11
-rw-r--r--lib/models/Courseware/BlockTypes/IFrame.php7
-rw-r--r--lib/models/Courseware/BlockTypes/ImageMap.php6
-rw-r--r--lib/models/Courseware/BlockTypes/KeyPoint.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Link.php7
-rw-r--r--lib/models/Courseware/BlockTypes/Lti.php7
-rw-r--r--lib/models/Courseware/BlockTypes/TableOfContents.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Text.php10
-rw-r--r--lib/models/Courseware/BlockTypes/Timeline.php7
-rw-r--r--lib/models/Courseware/BlockTypes/Typewriter.php6
-rw-r--r--lib/models/Courseware/BlockTypes/Video.php7
-rw-r--r--lib/models/Courseware/ContainerTypes/AccordionContainer.php6
-rw-r--r--lib/models/Courseware/ContainerTypes/ContainerType.php15
-rw-r--r--lib/models/Courseware/ContainerTypes/ListContainer.php7
-rw-r--r--lib/models/Courseware/ContainerTypes/TabsContainer.php7
-rw-r--r--lib/models/CronjobLog.php (renamed from lib/models/CronjobLog.class.php)2
-rw-r--r--lib/models/CronjobSchedule.php (renamed from lib/models/CronjobSchedule.class.php)74
-rw-r--r--lib/models/CronjobTask.php (renamed from lib/models/CronjobTask.class.php)70
-rw-r--r--lib/models/DataField.php (renamed from lib/models/DataField.class.php)5
-rw-r--r--lib/models/DatafieldEntryModel.php (renamed from lib/models/DatafieldEntryModel.class.php)0
-rw-r--r--lib/models/DatafieldEntryModelI18N.php (renamed from lib/models/DatafieldEntryModelI18N.class.php)0
-rw-r--r--lib/models/Degree.php (renamed from lib/models/Degree.class.php)2
-rw-r--r--lib/models/Deputy.php2
-rw-r--r--lib/models/FileRef.php3
-rw-r--r--lib/models/Folder.php3
-rw-r--r--lib/models/Freetext.php17
-rw-r--r--lib/models/Grading/Instance.php18
-rw-r--r--lib/models/HelpContent.php (renamed from lib/models/HelpContent.class.php)2
-rw-r--r--lib/models/HelpTour.php (renamed from lib/models/HelpTour.class.php)2
-rw-r--r--lib/models/HelpTourAudience.php (renamed from lib/models/HelpTourAudience.class.php)2
-rw-r--r--lib/models/HelpTourSettings.php (renamed from lib/models/HelpTourSettings.class.php)2
-rw-r--r--lib/models/HelpTourStep.php (renamed from lib/models/HelpTourStep.class.php)3
-rw-r--r--lib/models/HelpTourUser.php (renamed from lib/models/HelpTourUser.class.php)2
-rw-r--r--lib/models/Institute.php (renamed from lib/models/Institute.class.php)2
-rw-r--r--lib/models/InstituteMember.php (renamed from lib/models/InstituteMember.class.php)0
-rw-r--r--lib/models/InstitutePlanColumn.php (renamed from lib/models/InstitutePlanColumn.class.php)0
-rw-r--r--lib/models/Kategorie.php (renamed from lib/models/Kategorie.class.php)0
-rw-r--r--lib/models/LikertScale.php8
-rw-r--r--lib/models/LockRule.php (renamed from lib/models/LockRule.class.php)2
-rw-r--r--lib/models/LoginBackground.php (renamed from lib/models/LoginBackground.class.php)2
-rw-r--r--lib/models/LoginFaq.php (renamed from lib/models/LoginFaq.class.php)2
-rw-r--r--lib/models/Lvgruppe.php12
-rw-r--r--lib/models/MailQueueEntry.php (renamed from lib/models/MailQueueEntry.class.php)2
-rw-r--r--lib/models/Message.php (renamed from lib/models/Message.class.php)2
-rw-r--r--lib/models/MessageUser.php (renamed from lib/models/MessageUser.class.php)2
-rw-r--r--lib/models/MvvOverlappingConflict.php (renamed from lib/models/MvvOverlappingConflict.class.php)2
-rw-r--r--lib/models/MvvOverlappingExclude.php3
-rw-r--r--lib/models/MvvOverlappingSelection.php (renamed from lib/models/MvvOverlappingSelection.class.php)2
-rw-r--r--lib/models/NewsRange.php (renamed from lib/models/NewsRange.class.php)2
-rw-r--r--lib/models/NewsRoles.php (renamed from lib/models/NewsRoles.class.php)2
-rw-r--r--lib/models/OERHostOERSI.php21
-rw-r--r--lib/models/OERMaterial.php8
-rw-r--r--lib/models/OpenGraphURL.php (renamed from lib/models/OpenGraphURL.class.php)0
-rw-r--r--lib/models/OpenGraphURLCollection.php (renamed from lib/models/OpenGraphURLCollection.class.php)0
-rw-r--r--lib/models/PersonalNotifications.php (renamed from lib/models/PersonalNotifications.class.php)6
-rw-r--r--lib/models/Questionnaire.php4
-rw-r--r--lib/models/QuestionnaireInfo.php4
-rw-r--r--lib/models/RangeScale.php16
-rw-r--r--lib/models/Semester.php (renamed from lib/models/Semester.class.php)8
-rw-r--r--lib/models/SemesterCourse.php (renamed from lib/models/SemesterCourse.class.php)2
-rw-r--r--lib/models/SemesterHoliday.php (renamed from lib/models/SemesterHoliday.class.php)2
-rw-r--r--lib/models/SeminarCycleDate.php (renamed from lib/models/SeminarCycleDate.class.php)2
-rw-r--r--lib/models/SimpleCollection.class.php788
-rw-r--r--lib/models/SimpleORMap.class.php2501
-rw-r--r--lib/models/SimpleORMapCollection.class.php261
-rw-r--r--lib/models/StudipCacheOperation.php2
-rw-r--r--lib/models/StudipComment.php (renamed from lib/models/StudipComment.class.php)2
-rw-r--r--lib/models/StudipEvaluation.php90
-rw-r--r--lib/models/StudipNews.php (renamed from lib/models/StudipNews.class.php)19
-rw-r--r--lib/models/StudipScmEntry.php (renamed from lib/models/StudipScmEntry.class.php)2
-rw-r--r--lib/models/StudipStudyArea.php (renamed from lib/models/StudipStudyArea.class.php)0
-rw-r--r--lib/models/StudyCourse.php (renamed from lib/models/StudyCourse.class.php)2
-rw-r--r--lib/models/ToolActivation.php2
-rw-r--r--lib/models/User.php (renamed from lib/models/User.class.php)68
-rw-r--r--lib/models/UserInfo.php (renamed from lib/models/UserInfo.class.php)2
-rw-r--r--lib/models/UserOnline.php (renamed from lib/models/UserOnline.class.php)4
-rw-r--r--lib/models/UserStudyCourse.php (renamed from lib/models/UserStudyCourse.class.php)2
-rw-r--r--lib/models/Vote.php49
-rw-r--r--lib/models/WebserviceAccessRule.php (renamed from lib/models/WebserviceAccessRule.class.php)2
-rw-r--r--lib/models/WikiPage.php (renamed from lib/models/WikiPage.class.php)5
-rw-r--r--lib/models/calendar/CalendarCourseDate.class.php34
-rw-r--r--lib/models/calendar/CalendarCourseDate.php80
-rw-r--r--lib/models/calendar/CalendarCourseExDate.php (renamed from lib/models/calendar/CalendarCourseExDate.class.php)0
-rw-r--r--lib/models/calendar/CalendarDate.php (renamed from lib/models/calendar/CalendarDate.class.php)8
-rw-r--r--lib/models/calendar/CalendarDateAssignment.php (renamed from lib/models/calendar/CalendarDateAssignment.class.php)10
-rw-r--r--lib/models/calendar/CalendarDateException.php (renamed from lib/models/calendar/CalendarDateException.class.php)0
-rw-r--r--lib/models/resources/BrokenResource.php (renamed from lib/models/resources/BrokenResource.class.php)2
-rw-r--r--lib/models/resources/Building.php (renamed from lib/models/resources/Building.class.php)2
-rw-r--r--lib/models/resources/GlobalResourceLock.php (renamed from lib/models/resources/GlobalResourceLock.class.php)2
-rw-r--r--lib/models/resources/Location.php (renamed from lib/models/resources/Location.class.php)2
-rw-r--r--lib/models/resources/Resource.php (renamed from lib/models/resources/Resource.class.php)33
-rw-r--r--lib/models/resources/ResourceBooking.php (renamed from lib/models/resources/ResourceBooking.class.php)22
-rw-r--r--lib/models/resources/ResourceBookingInterval.php (renamed from lib/models/resources/ResourceBookingInterval.class.php)2
-rw-r--r--lib/models/resources/ResourceCategory.php (renamed from lib/models/resources/ResourceCategory.class.php)4
-rw-r--r--lib/models/resources/ResourceCategoryProperty.php (renamed from lib/models/resources/ResourceCategoryProperty.class.php)2
-rw-r--r--lib/models/resources/ResourceLabel.php (renamed from lib/models/resources/ResourceLabel.class.php)2
-rw-r--r--lib/models/resources/ResourcePermission.php (renamed from lib/models/resources/ResourcePermission.class.php)2
-rw-r--r--lib/models/resources/ResourceProperty.php (renamed from lib/models/resources/ResourceProperty.class.php)2
-rw-r--r--lib/models/resources/ResourcePropertyDefinition.php (renamed from lib/models/resources/ResourcePropertyDefinition.class.php)4
-rw-r--r--lib/models/resources/ResourcePropertyGroup.php (renamed from lib/models/resources/ResourcePropertyGroup.class.php)2
-rw-r--r--lib/models/resources/ResourceRequest.php (renamed from lib/models/resources/ResourceRequest.class.php)70
-rw-r--r--lib/models/resources/ResourceRequestAppointment.php (renamed from lib/models/resources/ResourceRequestAppointment.class.php)2
-rw-r--r--lib/models/resources/ResourceRequestProperty.php (renamed from lib/models/resources/ResourceRequestProperty.class.php)2
-rw-r--r--lib/models/resources/ResourceTemporaryPermission.php (renamed from lib/models/resources/ResourceTemporaryPermission.class.php)2
-rw-r--r--lib/models/resources/Room.php (renamed from lib/models/resources/Room.class.php)2
-rw-r--r--lib/models/resources/RoomRequest.php (renamed from lib/models/resources/RoomRequest.class.php)2
-rw-r--r--lib/models/resources/SeparableRoom.php (renamed from lib/models/resources/SeparableRoom.class.php)2
-rw-r--r--lib/models/resources/SeparableRoomPart.php (renamed from lib/models/resources/SeparableRoomPart.class.php)2
152 files changed, 685 insertions, 4228 deletions
diff --git a/lib/models/AdmissionApplication.class.php b/lib/models/AdmissionApplication.php
index 02514ec..7e8c3f5 100644
--- a/lib/models/AdmissionApplication.class.php
+++ b/lib/models/AdmissionApplication.php
@@ -1,6 +1,6 @@
<?php
/**
- * AdmissionApplication.class.php
+ * AdmissionApplication.php
* model class for table admission_seminar_user
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/ArchivedCourse.class.php b/lib/models/ArchivedCourse.php
index 81879af..f3b2de8 100644
--- a/lib/models/ArchivedCourse.class.php
+++ b/lib/models/ArchivedCourse.php
@@ -1,6 +1,6 @@
<?php
/**
- * ArchivedCourse.class.php
+ * ArchivedCourse.php
* model class for table archiv
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/ArchivedCourseMember.class.php b/lib/models/ArchivedCourseMember.php
index 1febd35..e54de91 100644
--- a/lib/models/ArchivedCourseMember.class.php
+++ b/lib/models/ArchivedCourseMember.php
@@ -1,6 +1,6 @@
<?php
/**
- * ArchivedCourseMember.class.php
+ * ArchivedCourseMember.php
* model class for table seminar_user
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/AuthUserMd5.class.php b/lib/models/AuthUserMd5.php
index 48e27f8..d8b7c53 100644
--- a/lib/models/AuthUserMd5.class.php
+++ b/lib/models/AuthUserMd5.php
@@ -1,6 +1,6 @@
<?php
/**
- * AuthUserMd5.class.php
+ * AuthUserMd5.php
* model class for table auth_user_md5
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/AuxLockRule.php b/lib/models/AuxLockRule.php
index abd3327..f5ebfac 100644
--- a/lib/models/AuxLockRule.php
+++ b/lib/models/AuxLockRule.php
@@ -164,7 +164,7 @@ class AuxLockRule extends SimpleORMap
foreach ($this->datafields as $field => $useless_value_pls_refactor) {
// if standard get it from the mapping else get it from the datafield
- if ($mapping[$field]) {
+ if (!empty($mapping[$field])) {
$result['head'][$field] = $head_mapping[$field];
$new[$field] = htmlReady($mapping[$field]);
} else {
diff --git a/lib/models/Banner.class.php b/lib/models/Banner.php
index a418760..a418760 100644
--- a/lib/models/Banner.class.php
+++ b/lib/models/Banner.php
diff --git a/lib/models/BannerRoles.class.php b/lib/models/BannerRoles.php
index d1c2986..a460986 100644
--- a/lib/models/BannerRoles.class.php
+++ b/lib/models/BannerRoles.php
@@ -1,7 +1,7 @@
<?php
/**
- * BannerRoles.class.php - model class for the banner roles
+ * BannerRoles.php - model class for the banner roles
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/BlubberThread.php b/lib/models/BlubberThread.php
index 2bc78a9..590a600 100644
--- a/lib/models/BlubberThread.php
+++ b/lib/models/BlubberThread.php
@@ -470,7 +470,7 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
if (
isset($nav)
&& $nav->isVisible(true)
- && count($module->getTabNavigation($this['context_id'])) > 0
+ && $module->getTabNavigation($this['context_id'])
&& $GLOBALS['perm']->have_studip_perm($tool->getVisibilityPermission(), $this['context_id'])
) {
$icons[] = $nav;
@@ -1081,7 +1081,7 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
FROM user_inst
WHERE user_id = ?";
$institut_ids = DBManager::get()->fetchFirst($query, [$user_id]);
- $blubberplugin = PluginManager::getInstance()->getPlugin("Blubber");
+ $blubberplugin = PluginManager::getInstance()->getPlugin(Blubber::class);
if (!$blubberplugin) {
return [];
}
diff --git a/lib/models/CaptchaChallenge.php b/lib/models/CaptchaChallenge.php
new file mode 100644
index 0000000..446985d
--- /dev/null
+++ b/lib/models/CaptchaChallenge.php
@@ -0,0 +1,88 @@
+<?php
+final class CaptchaChallenge extends SimpleORMap
+{
+ public const ALGORITHM = 'SHA-256';
+ public const CHALLENGE_EXPIRATION = 5 * 60;
+
+ protected static function configure($config = [])
+ {
+ $config['db_table'] = 'captcha_challenges';
+
+ parent::configure($config);
+ }
+
+ protected static function getKey(): string
+ {
+ $key = Config::get()->CAPTCHA_KEY;
+ if ($key === '') {
+ $key = bin2hex(random_bytes(32));
+ Config::get()->store('CAPTCHA_KEY', $key);
+ }
+ return $key;
+ }
+
+ public static function createChallenge(string $salt, int $number): array
+ {
+ $algorithm = 'sha256';
+ $challenge = hash($algorithm, $salt . $number);
+ $signature = hash_hmac($algorithm, $challenge, self::getKey());
+
+ return [
+ 'algorithm' => self::ALGORITHM,
+ 'challenge' => $challenge,
+ 'salt' => $salt,
+ 'signature' => $signature,
+ ];
+ }
+
+ public static function createNewChallenge(): array
+ {
+ do {
+ $salt = time() . '-' . bin2hex(random_bytes(12));
+ $number = random_int(1e3, 1e5);
+ } while (self::countBySql('salt = ? AND number = ?', [$salt, $number]) > 0);
+
+ return self::createChallenge($salt, $number);
+ }
+
+ public static function decodePayload(string $payload): array|null
+ {
+ return json_decode(base64_decode($payload), true);
+ }
+
+ public static function validatePayload(string $payload): string|bool
+ {
+ $json = self::decodePayload($payload);
+
+ if ($json === null) {
+ return _('Sie haben nicht bestätigt, dass Sie kein Roboter sind');
+ }
+
+ $time = explode('-', $json['salt'])[0];
+ if ($time < time() - self::CHALLENGE_EXPIRATION) {
+ return _('Die Challenge ist abgelaufen');
+ }
+
+ // Replay?
+ if (\CaptchaChallenge::countBySql('salt = ? AND number = ?', [$json['salt'], $json['number']]) > 0) {
+ return _('Nicht schummeln!');
+ }
+
+ $check = self::createChallenge($json['salt'], $json['number']);
+
+ if (
+ $json['algorithm'] !== $check['algorithm']
+ || $json['challenge'] !== $check['challenge']
+ || $json['signature'] !== $check['signature']
+ ) {
+ return _('Sie sind scheinbar ein Roboter...');
+ }
+
+ return true;
+ }
+
+ public static function gc(): void
+ {
+ self::deleteBySQL("mkdate < UNIX_TIMESTAMP() - ?", [self::CHALLENGE_EXPIRATION]);
+ }
+}
diff --git a/lib/models/Clipboard.class.php b/lib/models/Clipboard.php
index cd8fe89..01282cc 100644
--- a/lib/models/Clipboard.class.php
+++ b/lib/models/Clipboard.php
@@ -2,7 +2,7 @@
/**
- * Clipboard.class.php - model class for a clipboard (Merkzettel)
+ * Clipboard.php - model class for a clipboard (Merkzettel)
*
* The Clipboard class extends the wish list functionality of the clipboard
* in the old literature management to allow it to be used in other areas of the
diff --git a/lib/models/ClipboardItem.class.php b/lib/models/ClipboardItem.php
index 030388a..a19eeaf 100644
--- a/lib/models/ClipboardItem.class.php
+++ b/lib/models/ClipboardItem.php
@@ -1,6 +1,6 @@
<?php
/**
- * ClipboardItem.class.php - model class for clipboard items
+ * ClipboardItem.php - model class for clipboard items
* (Merkzettel-Einträge)
*
* The ClipboardItem class holds single items of a clipboard.
@@ -23,6 +23,8 @@
* @property int $mkdate database column
* @property int $chdate database column
* @property Clipboard $clipboard belongs_to Clipboard
+ *
+ * @property-read string $name
*/
class ClipboardItem extends SimpleORMap
{
@@ -36,36 +38,32 @@ class ClipboardItem extends SimpleORMap
'assoc_func' => 'find'
];
+ $config['additional_fields']['name'] = [
+ 'get' => fn(ClipboardItem $item) => $item->__toString(),
+ ];
+
parent::configure($config);
}
-
/**
* @returns string representation of this clipboard item.
*/
public function __toString()
{
- //Get the class $range_type and the object with ID $range_id,
- //if $range_type is a StudipItem:
-
- $use_generic_name = true;
- $object = null;
- if (is_subclass_of($this->range_type, 'StudipItem', true)) {
+ // Get the class $range_type and the object with ID $range_id,
+ // if $range_type is a StudipItem:
+ if (is_subclass_of($this->range_type, StudipItem::class)) {
$range_class_name = $this->range_type;
$object = $range_class_name::find($this->range_id);
if ($object) {
- $use_generic_name = false;
+ return $object->getItemName(false);
}
}
- if ($use_generic_name) {
- //$range_type is not a class name of a StudipItem class
- //or no object of a StudipItem class could be found:
- //We cannot determine the name and must therefore use
- //a generic name:
- return $this->range_type . '_' . $this->range_id;
- } else {
- return $object->getItemName(false);
- }
+ // $range_type is not a class name of a StudipItem class
+ // or no object of a StudipItem class could be found:
+ // We cannot determine the name and must therefore use
+ // a generic name:
+ return $this->range_type . '_' . $this->range_id;
}
}
diff --git a/lib/models/ColourValue.class.php b/lib/models/ColourValue.php
index 6ae05ad..486de45 100644
--- a/lib/models/ColourValue.class.php
+++ b/lib/models/ColourValue.php
@@ -1,7 +1,7 @@
<?php
/**
- * ColorValue.class.php
+ * ColorValue.php
* model class for table color_values
*
* Objects of this class holds a colour's name (its purpose)
diff --git a/lib/models/ConfigEntry.class.php b/lib/models/ConfigEntry.php
index 5e06da8..dd0efa4 100644
--- a/lib/models/ConfigEntry.class.php
+++ b/lib/models/ConfigEntry.php
@@ -1,6 +1,6 @@
<?php
/**
- * ConfigEntry.class.php
+ * ConfigEntry.php
* model class for table user_config
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/ConsultationBlock.php b/lib/models/ConsultationBlock.php
index e42daaf..cde8f77 100644
--- a/lib/models/ConsultationBlock.php
+++ b/lib/models/ConsultationBlock.php
@@ -25,6 +25,7 @@
* @property string $note database column
* @property int $size database column
* @property int|null $lock_time database column
+ * @property bool $consecutive database column
* @property int $mkdate database column
* @property int $chdate database column
* @property SimpleORMapCollection|ConsultationSlot[] $slots has_many ConsultationSlot
@@ -71,7 +72,7 @@ class ConsultationBlock extends SimpleORMap implements PrivacyObject
if ($block->range instanceof User) {
return $block->range->getFullName() . ' <' . $block->range->email . '>';
}
- if ($block->range instanceof Course || $block->range instanceof Institute) {
+ if ($block->range instanceof Course) {
return sprintf(_('Veranstaltung: %s'), $block->range->getFullName());
}
@@ -211,6 +212,10 @@ class ConsultationBlock extends SimpleORMap implements PrivacyObject
);
}
+ if (!$interval) {
+ break;
+ }
+
$current = strtotime("+{$interval} weeks", $current);
}
@@ -274,9 +279,9 @@ class ConsultationBlock extends SimpleORMap implements PrivacyObject
}
$slots[] = ConsultationSlot::build([
- 'block_id' => $this->id,
- 'start_time' => $now,
- 'end_time' => strtotime("+{$duration} minutes", $now),
+ 'block_id' => $this->id,
+ 'start_time' => $now,
+ 'end_time' => strtotime("+{$duration} minutes", $now),
]);
$now = strtotime("+{$duration} minutes", $now);
diff --git a/lib/models/ConsultationSlot.php b/lib/models/ConsultationSlot.php
index 0da02df..c46e47c 100644
--- a/lib/models/ConsultationSlot.php
+++ b/lib/models/ConsultationSlot.php
@@ -9,6 +9,7 @@
* @property int $id alias column for slot_id
* @property int $slot_id database column
* @property int $block_id database column
+ * @property int $previous_slot_id database column
* @property int $start_time database column
* @property int $end_time database column
* @property string $note database column
@@ -17,6 +18,7 @@
* @property SimpleORMapCollection|ConsultationBooking[] $bookings has_many ConsultationBooking
* @property SimpleORMapCollection|ConsultationEvent[] $events has_many ConsultationEvent
* @property ConsultationBlock $block belongs_to ConsultationBlock
+ * @property ConsultationSlot|null $previous_slot has_one ConsultationSlot
* @property-read mixed $has_bookings additional field
* @property-read mixed $is_expired additional field
*/
@@ -45,15 +47,36 @@ class ConsultationSlot extends SimpleORMap
'assoc_foreign_key' => 'slot_id',
'on_delete' => 'delete',
];
+ $config['has_one']['previous_slot'] = [
+ 'class_name' => ConsultationSlot::class,
+ 'foreign_key' => 'previous_slot_id',
+ ];
$config['registered_callbacks']['before_create'][] = function (ConsultationSlot $slot) {
$slot->updateEvents();
};
+ $config['registered_callbacks']['before_store'][] = function (ConsultationSlot $slot) {
+ $previous = static::findOneBySQL(
+ "block_id = ? AND start_time < ? ORDER BY start_time DESC",
+ [$slot->block_id, $slot->start_time]
+ );
+ $slot->previous_slot_id = $previous?->id;
+ };
$config['registered_callbacks']['after_delete'][] = function ($slot) {
$block = $slot->block;
if ($block && count($block->slots) === 0) {
$block->delete();
}
+
+ // Close gap
+ self::findEachBySQL(
+ function (ConsultationSlot $s) use ($slot) {
+ $s->previous_slot_id = $slot->previous_slot_id;
+ $s->store();
+ },
+ 'previous_slot_id = ?',
+ [$slot->id]
+ );
};
$config['additional_fields']['has_bookings']['get'] = function ($slot): bool {
@@ -139,10 +162,6 @@ class ConsultationSlot extends SimpleORMap
/**
* Returns whether this slot is occupied (by a given user).
- *
- * @param mixed $user_id Id of the user (optional)
- * @return boolean indicating whether the slot is occupied (by the given
- * user)
*/
public function isOccupied($user_id = null)
{
@@ -154,7 +173,6 @@ class ConsultationSlot extends SimpleORMap
/**
* Returns whether the slot is locked for bookings.
*
- * @return bool
*/
public function isLocked(): bool
{
@@ -163,6 +181,20 @@ class ConsultationSlot extends SimpleORMap
}
/**
+ * Returns whether the slot is bookable for the given user_id
+ */
+ public function isBookable(?string $user_id = null): bool
+ {
+ return !$this->isOccupied($user_id)
+ && !$this->isLocked()
+ && !(
+ $this->block->consecutive
+ && $this->previous_slot
+ && !$this->previous_slot->isOccupied()
+ );
+ }
+
+ /**
* Creates a Stud.IP calendar event relating to the slot.
*
* @param User $user User object to create the event for
@@ -306,8 +338,7 @@ class ConsultationSlot extends SimpleORMap
$user = $user ?? User::findCurrent();
return ConsultationBooking::userMayCreateBookingForRange($this->block->range, $user)
- && !$this->isOccupied()
- && !$this->isLocked();
+ && $this->isBookable($user->id);
}
diff --git a/lib/models/Contact.class.php b/lib/models/Contact.php
index 16bff26..bea5b95 100644
--- a/lib/models/Contact.class.php
+++ b/lib/models/Contact.php
@@ -1,7 +1,7 @@
<?php
/**
- * Contact.class.php - model class for table contact
+ * Contact.php - model class for table contact
*
* @author <mlunzena@uos.de>
* @license GPL 2 or later
diff --git a/lib/models/ContactGroup.class.php b/lib/models/ContactGroup.php
index 0e60d3b..0e60d3b 100644
--- a/lib/models/ContactGroup.class.php
+++ b/lib/models/ContactGroup.php
diff --git a/lib/models/ContactGroupItem.class.php b/lib/models/ContactGroupItem.php
index 0204d0a..0204d0a 100644
--- a/lib/models/ContactGroupItem.class.php
+++ b/lib/models/ContactGroupItem.php
diff --git a/lib/models/ContentTermsOfUse.class.php b/lib/models/ContentTermsOfUse.php
index fb2e592..1982dd6 100644
--- a/lib/models/ContentTermsOfUse.class.php
+++ b/lib/models/ContentTermsOfUse.php
@@ -1,6 +1,6 @@
<?php
/**
- * ContentTermsOfUse.class.php
+ * ContentTermsOfUse.php
* model class for table licenses
*
* The ContentTermsOfUse class provides information about the terms under which
diff --git a/lib/models/Course.class.php b/lib/models/Course.php
index 59f9b82..d8bb2f5 100644
--- a/lib/models/Course.class.php
+++ b/lib/models/Course.php
@@ -1,6 +1,6 @@
<?php
/**
- * Course.class.php
+ * Course.php
* model class for table seminare
*
* This program is free software; you can redistribute it and/or
@@ -306,19 +306,27 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
/**
* Returns the associated mvv modules for a given course id.
*
- * @param string $course_id
+ * @param string $course_id
+ * @param array|null $statusses Limit the results by a given module status
* @return Modul[]
*/
- public static function getMVVModulesForCourseId(string $course_id): array
+ public static function getMVVModulesForCourseId(string $course_id, ?array $statusses = null): array
{
$query = "SELECT mvv_modul.*
FROM mvv_lvgruppe_seminar
- JOIN `mvv_lvgruppe` on(`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe`.`lvgruppe_id`)
- JOIN `mvv_lvgruppe_modulteil` on(`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe_modulteil`.`lvgruppe_id`)
- JOIN `mvv_modulteil` on(`mvv_lvgruppe_modulteil`.`modulteil_id` = `mvv_modulteil`.`modulteil_id`)
- JOIN `mvv_modul` on(`mvv_modulteil`.`modul_id` = `mvv_modul`.`modul_id`)
+ JOIN `mvv_lvgruppe` ON (`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe`.`lvgruppe_id`)
+ JOIN `mvv_lvgruppe_modulteil` ON (`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe_modulteil`.`lvgruppe_id`)
+ JOIN `mvv_modulteil` ON (`mvv_lvgruppe_modulteil`.`modulteil_id` = `mvv_modulteil`.`modulteil_id`)
+ JOIN `mvv_modul` ON (`mvv_modulteil`.`modul_id` = `mvv_modul`.`modul_id`)
WHERE seminar_id = ?";
- return DBManager::get()->fetchAll($query, [$course_id], function ($row) {
+ $parameters = [$course_id];
+
+ if ($statusses !== null) {
+ $query .= ' AND `mvv_modul`.`stat` IN (?)';
+ $parameters[] = $statusses;
+ }
+
+ return DBManager::get()->fetchAll($query, $parameters, function ($row) {
return Modul::buildExisting($row);
});
}
diff --git a/lib/models/CourseDate.class.php b/lib/models/CourseDate.php
index ac0c8c3..eadeb0a 100644
--- a/lib/models/CourseDate.class.php
+++ b/lib/models/CourseDate.php
@@ -364,7 +364,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
// load room-booking, if any
$this->room_booking;
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/'. $this->range_id);
return parent::store();
}
@@ -376,7 +376,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
*/
public function delete()
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/'. $this->range_id);
return parent::delete();
}
@@ -433,7 +433,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
$folders = array_merge($folders, $topic->folders->getArrayCopy());
}
foreach ($folders as $folder) {
- list($files, $typed_folders) = array_values(FileManager::getFolderFilesRecursive($folder->getTypedFolder(), $user_id));
+ [$files, $typed_folders] = array_values(FileManager::getFolderFilesRecursive($folder->getTypedFolder(), $user_id));
foreach ($files as $file) {
$all_files[$file->id] = $file;
}
@@ -633,7 +633,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
);
$class_names = [];
if ($membership) {
- $class_names[] = sprintf('gruppe%u', $membership->status);
+ $class_names[] = 'course-color-' . $membership->gruppe;
}
$studip_view_urls = [];
if ($GLOBALS['perm']->have_studip_perm('user', $this->range_id, $user_id)) {
diff --git a/lib/models/CourseExDate.class.php b/lib/models/CourseExDate.php
index 2d3afea..2d3afea 100644
--- a/lib/models/CourseExDate.class.php
+++ b/lib/models/CourseExDate.php
diff --git a/lib/models/CourseMember.class.php b/lib/models/CourseMember.php
index cd7555f..7c4b335 100644
--- a/lib/models/CourseMember.class.php
+++ b/lib/models/CourseMember.php
@@ -1,6 +1,6 @@
<?php
/**
- * CourseMember.class.php
+ * CourseMember.php
* model class for table seminar_user
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/CourseMemberNotification.php b/lib/models/CourseMemberNotification.php
index e72ba76..5e1b544 100644
--- a/lib/models/CourseMemberNotification.php
+++ b/lib/models/CourseMemberNotification.php
@@ -1,6 +1,6 @@
<?php
/**
- * CourseMemberNotification.class.php
+ * CourseMemberNotification.php
* model class for table seminar_user_notification
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/CourseTopic.class.php b/lib/models/CourseTopic.php
index eb26efa..eb26efa 100644
--- a/lib/models/CourseTopic.class.php
+++ b/lib/models/CourseTopic.php
diff --git a/lib/models/Courseware/BlockTypes/Audio.php b/lib/models/Courseware/BlockTypes/Audio.php
index dd2588a..22dc167 100644
--- a/lib/models/Courseware/BlockTypes/Audio.php
+++ b/lib/models/Courseware/BlockTypes/Audio.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware audio block.
*
@@ -42,11 +40,10 @@ class Audio extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Audio.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
diff --git a/lib/models/Courseware/BlockTypes/BeforeAfter.php b/lib/models/Courseware/BlockTypes/BeforeAfter.php
index b4f33ca..e174bff 100644
--- a/lib/models/Courseware/BlockTypes/BeforeAfter.php
+++ b/lib/models/Courseware/BlockTypes/BeforeAfter.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware before after block.
*
@@ -41,11 +39,10 @@ class BeforeAfter extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/BeforeAfter.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
diff --git a/lib/models/Courseware/BlockTypes/BiographyAchievements.php b/lib/models/Courseware/BlockTypes/BiographyAchievements.php
index 3af5d64..2f8aeb7 100644
--- a/lib/models/Courseware/BlockTypes/BiographyAchievements.php
+++ b/lib/models/Courseware/BlockTypes/BiographyAchievements.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware biography achievements block.
*
@@ -57,11 +55,10 @@ class BiographyAchievements extends BlockType
parent::setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/BiographyAchievements.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/BiographyCareer.php b/lib/models/Courseware/BlockTypes/BiographyCareer.php
index ebd1a85..9425cfe 100644
--- a/lib/models/Courseware/BlockTypes/BiographyCareer.php
+++ b/lib/models/Courseware/BlockTypes/BiographyCareer.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware biography career block.
*
@@ -48,11 +46,11 @@ class BiographyCareer extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/BiographyCareer.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/BiographyGoals.php b/lib/models/Courseware/BlockTypes/BiographyGoals.php
index dcfb76c..b4f1b64 100644
--- a/lib/models/Courseware/BlockTypes/BiographyGoals.php
+++ b/lib/models/Courseware/BlockTypes/BiographyGoals.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware biography personal goals block.
*
@@ -53,11 +51,11 @@ class BiographyGoals extends BlockType
parent::setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/BiographyGoals.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/BiographyPersonalInformation.php b/lib/models/Courseware/BlockTypes/BiographyPersonalInformation.php
index 8f3c0c1..bb11f53 100644
--- a/lib/models/Courseware/BlockTypes/BiographyPersonalInformation.php
+++ b/lib/models/Courseware/BlockTypes/BiographyPersonalInformation.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware biography personal information block.
*
@@ -41,11 +39,11 @@ class BiographyPersonalInformation extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/BiographyPersonalInformation.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/BlockType.php b/lib/models/Courseware/BlockTypes/BlockType.php
index b3d5abf..37e617b 100644
--- a/lib/models/Courseware/BlockTypes/BlockType.php
+++ b/lib/models/Courseware/BlockTypes/BlockType.php
@@ -3,7 +3,6 @@
namespace Courseware\BlockTypes;
use Courseware\CoursewarePlugin;
-use Opis\JsonSchema\Schema;
use Opis\JsonSchema\Validator;
/**
@@ -52,9 +51,9 @@ abstract class BlockType
* Returns the JSON schema which is used to validate the payload of
* instances of this type of block.
*
- * @return Schema the JSON schema to be used
+ * @return string the JSON schema to be used
*/
- abstract public static function getJsonSchema(): Schema;
+ abstract public static function getJsonSchema(): string;
/**
* Returns a list of categories to which this type of block is associated.
@@ -192,10 +191,8 @@ abstract class BlockType
*/
public function validatePayload($payload): bool
{
- $schema = static::getJsonSchema();
$validator = new Validator();
- $result = $validator->schemaValidation($payload, $schema);
-
+ $result = $validator->validate($payload, static::getJsonSchema());
return $result->isValid();
}
@@ -441,9 +438,9 @@ abstract class BlockType
* It turns the classname into snakecase in order to find the
* template file in templates/courseware/block_types.
*
- * @return mixed the \Flexi_Template instance if exists, otherwise null.
+ * @return \Flexi\Template|null the \Flexi\Template instance if exists, otherwise null.
*/
- public function getPdfHtmlTemplate(): ?\Flexi_Template
+ public function getPdfHtmlTemplate(): ?\Flexi\Template
{
$template = null;
try {
diff --git a/lib/models/Courseware/BlockTypes/Canvas.php b/lib/models/Courseware/BlockTypes/Canvas.php
index e7b14e9..cc2196a 100644
--- a/lib/models/Courseware/BlockTypes/Canvas.php
+++ b/lib/models/Courseware/BlockTypes/Canvas.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware canvas block.
*
@@ -40,11 +38,11 @@ class Canvas extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Canvas.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
diff --git a/lib/models/Courseware/BlockTypes/Chart.php b/lib/models/Courseware/BlockTypes/Chart.php
index 196e90f..147c3c5 100644
--- a/lib/models/Courseware/BlockTypes/Chart.php
+++ b/lib/models/Courseware/BlockTypes/Chart.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware chart block.
*
@@ -38,11 +36,11 @@ class Chart extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Chart.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Code.php b/lib/models/Courseware/BlockTypes/Code.php
index 5b1454c..d5bd1c5 100644
--- a/lib/models/Courseware/BlockTypes/Code.php
+++ b/lib/models/Courseware/BlockTypes/Code.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware code block.
*
@@ -37,11 +35,11 @@ class Code extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Code.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Confirm.php b/lib/models/Courseware/BlockTypes/Confirm.php
index bb6738d..2c25316 100644
--- a/lib/models/Courseware/BlockTypes/Confirm.php
+++ b/lib/models/Courseware/BlockTypes/Confirm.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware confirm block.
*
@@ -36,11 +34,11 @@ class Confirm extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Confirm.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Date.php b/lib/models/Courseware/BlockTypes/Date.php
index 46e77d8..548e648 100644
--- a/lib/models/Courseware/BlockTypes/Date.php
+++ b/lib/models/Courseware/BlockTypes/Date.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware date block.
*
@@ -37,11 +35,11 @@ class Date extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Date.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/DialogCards.php b/lib/models/Courseware/BlockTypes/DialogCards.php
index 74b843c..875a0b3 100644
--- a/lib/models/Courseware/BlockTypes/DialogCards.php
+++ b/lib/models/Courseware/BlockTypes/DialogCards.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware dialog cards block.
*
@@ -96,11 +94,11 @@ class DialogCards extends BlockType
return $payload;
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/DialogCards.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Document.php b/lib/models/Courseware/BlockTypes/Document.php
index db1ba6e..562ec08 100644
--- a/lib/models/Courseware/BlockTypes/Document.php
+++ b/lib/models/Courseware/BlockTypes/Document.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware document block.
*
@@ -39,11 +37,10 @@ class Document extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Document.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
diff --git a/lib/models/Courseware/BlockTypes/Download.php b/lib/models/Courseware/BlockTypes/Download.php
index d736009..e7bb65c 100644
--- a/lib/models/Courseware/BlockTypes/Download.php
+++ b/lib/models/Courseware/BlockTypes/Download.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware download block.
*
@@ -72,11 +70,11 @@ class Download extends BlockType
return $payload;
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Download.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Embed.php b/lib/models/Courseware/BlockTypes/Embed.php
index cb997ee..1b36624 100644
--- a/lib/models/Courseware/BlockTypes/Embed.php
+++ b/lib/models/Courseware/BlockTypes/Embed.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware embed block.
*
@@ -40,11 +38,10 @@ class Embed extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Embed.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public function getPayload()
diff --git a/lib/models/Courseware/BlockTypes/Error.php b/lib/models/Courseware/BlockTypes/Error.php
index 2e15456..3f290b1 100644
--- a/lib/models/Courseware/BlockTypes/Error.php
+++ b/lib/models/Courseware/BlockTypes/Error.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware error block.
*
@@ -34,11 +32,11 @@ class Error extends BlockType
return [];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Error.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Folder.php b/lib/models/Courseware/BlockTypes/Folder.php
index 2eed4b0..9f186df 100644
--- a/lib/models/Courseware/BlockTypes/Folder.php
+++ b/lib/models/Courseware/BlockTypes/Folder.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware folder block.
*
@@ -55,7 +53,7 @@ class Folder extends BlockType
if ($folder) {
$typedFolder = $folder->getTypedFolder();
$payload['folder-type'] = $typedFolder->folder_type;
- if ($typedFolder->isReadable($user->id)) {
+ if ($typedFolder->isReadable($user->id) || $typedFolder->folder_type === 'HomeworkFolder') {
foreach ($typedFolder->getFiles() as $folderFile) {
$file['id'] = $folderFile->id;
$file['attributes'] = [
@@ -116,11 +114,10 @@ class Folder extends BlockType
return $payload;
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Folder.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Gallery.php b/lib/models/Courseware/BlockTypes/Gallery.php
index 5f9bb0b..5041573 100644
--- a/lib/models/Courseware/BlockTypes/Gallery.php
+++ b/lib/models/Courseware/BlockTypes/Gallery.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware gallery block.
*
@@ -133,11 +131,11 @@ class Gallery extends BlockType
return $payload;
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Gallery.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Headline.php b/lib/models/Courseware/BlockTypes/Headline.php
index 0c82138..616af88 100644
--- a/lib/models/Courseware/BlockTypes/Headline.php
+++ b/lib/models/Courseware/BlockTypes/Headline.php
@@ -2,7 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
use Opis\JsonSchema\Validator;
/**
@@ -49,11 +48,10 @@ class Headline extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Headline.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
@@ -88,11 +86,8 @@ class Headline extends BlockType
public function validatePayload($payload): bool
{
unset($payload->background_image);
- $schema = static::getJsonSchema();
- $validator = new Validator();
- $result = $validator->schemaValidation($payload, $schema);
- return $result->isValid();
+ return parent::validatePayload($payload);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/IFrame.php b/lib/models/Courseware/BlockTypes/IFrame.php
index 5c914f9..f697e74 100644
--- a/lib/models/Courseware/BlockTypes/IFrame.php
+++ b/lib/models/Courseware/BlockTypes/IFrame.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware iFrame block.
*
@@ -45,11 +43,10 @@ class IFrame extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/IFrame.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/ImageMap.php b/lib/models/Courseware/BlockTypes/ImageMap.php
index e275c46..d9ad845 100644
--- a/lib/models/Courseware/BlockTypes/ImageMap.php
+++ b/lib/models/Courseware/BlockTypes/ImageMap.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware image map block.
*
@@ -66,11 +64,11 @@ class ImageMap extends BlockType
return $payload;
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/ImageMap.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/KeyPoint.php b/lib/models/Courseware/BlockTypes/KeyPoint.php
index 8599704..d1e6c34 100644
--- a/lib/models/Courseware/BlockTypes/KeyPoint.php
+++ b/lib/models/Courseware/BlockTypes/KeyPoint.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware key point block.
*
@@ -38,11 +36,11 @@ class KeyPoint extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/KeyPoint.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Link.php b/lib/models/Courseware/BlockTypes/Link.php
index ccf9f66..3282e2c 100644
--- a/lib/models/Courseware/BlockTypes/Link.php
+++ b/lib/models/Courseware/BlockTypes/Link.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware link block.
*
@@ -39,11 +37,10 @@ class Link extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Link.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Lti.php b/lib/models/Courseware/BlockTypes/Lti.php
index 8b527c1..193bfb5 100644
--- a/lib/models/Courseware/BlockTypes/Lti.php
+++ b/lib/models/Courseware/BlockTypes/Lti.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware LTI block.
*
@@ -44,11 +42,10 @@ class Lti extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Lti.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public function getPayload()
diff --git a/lib/models/Courseware/BlockTypes/TableOfContents.php b/lib/models/Courseware/BlockTypes/TableOfContents.php
index c48b683..f0485b9 100644
--- a/lib/models/Courseware/BlockTypes/TableOfContents.php
+++ b/lib/models/Courseware/BlockTypes/TableOfContents.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware table of contents block.
*
@@ -37,11 +35,11 @@ class TableOfContents extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/TableOfContents.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Text.php b/lib/models/Courseware/BlockTypes/Text.php
index 441da89..1da7cbe 100644
--- a/lib/models/Courseware/BlockTypes/Text.php
+++ b/lib/models/Courseware/BlockTypes/Text.php
@@ -2,9 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-require_once 'lib/classes/Markup.class.php';
-
/**
* This class represents the content of a Courseware text block.
*
@@ -66,11 +63,10 @@ class Text extends BlockType
parent::setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Text.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
@@ -192,7 +188,7 @@ class Text extends BlockType
}
- return array();
+ return null;
});
}
}
diff --git a/lib/models/Courseware/BlockTypes/Timeline.php b/lib/models/Courseware/BlockTypes/Timeline.php
index 81802ce..5647e92 100644
--- a/lib/models/Courseware/BlockTypes/Timeline.php
+++ b/lib/models/Courseware/BlockTypes/Timeline.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware timeline block.
*
@@ -45,11 +43,10 @@ class Timeline extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Timeline.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Typewriter.php b/lib/models/Courseware/BlockTypes/Typewriter.php
index 2544dde..b303fb3 100644
--- a/lib/models/Courseware/BlockTypes/Typewriter.php
+++ b/lib/models/Courseware/BlockTypes/Typewriter.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware typewriter block.
*
@@ -39,11 +37,11 @@ class Typewriter extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Typewriter.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
public static function getCategories(): array
diff --git a/lib/models/Courseware/BlockTypes/Video.php b/lib/models/Courseware/BlockTypes/Video.php
index 431f69b..1ad7064 100644
--- a/lib/models/Courseware/BlockTypes/Video.php
+++ b/lib/models/Courseware/BlockTypes/Video.php
@@ -2,8 +2,6 @@
namespace Courseware\BlockTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware video block.
*
@@ -42,11 +40,10 @@ class Video extends BlockType
];
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/Video.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
/**
diff --git a/lib/models/Courseware/ContainerTypes/AccordionContainer.php b/lib/models/Courseware/ContainerTypes/AccordionContainer.php
index 185b6d1..cd00a06 100644
--- a/lib/models/Courseware/ContainerTypes/AccordionContainer.php
+++ b/lib/models/Courseware/ContainerTypes/AccordionContainer.php
@@ -2,8 +2,6 @@
namespace Courseware\ContainerTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware accordion container stored in payload.
*
@@ -54,10 +52,10 @@ class AccordionContainer extends ContainerType
$this->setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/AccordionContainer.json';
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
}
diff --git a/lib/models/Courseware/ContainerTypes/ContainerType.php b/lib/models/Courseware/ContainerTypes/ContainerType.php
index e358c9c..4e816be 100644
--- a/lib/models/Courseware/ContainerTypes/ContainerType.php
+++ b/lib/models/Courseware/ContainerTypes/ContainerType.php
@@ -3,7 +3,6 @@
namespace Courseware\ContainerTypes;
use Courseware\CoursewarePlugin;
-use Opis\JsonSchema\Schema;
use Opis\JsonSchema\Validator;
/**
@@ -28,9 +27,9 @@ abstract class ContainerType
* Returns the JSON schema which is used to validate the payload of
* instances of this type of container.
*
- * @return Schema the JSON schema to be used
+ * @return string the JSON schema to be used
*/
- abstract public static function getJsonSchema(): Schema;
+ abstract public static function getJsonSchema(): string;
/**
* Returns a short string describing this type of container.
@@ -150,10 +149,8 @@ abstract class ContainerType
*/
public function validatePayload($payload): bool
{
- $schema = static::getJsonSchema();
$validator = new Validator();
- $result = $validator->schemaValidation($payload, $schema);
-
+ $result = $validator->validate($payload, static::getJsonSchema());
return $result->isValid();
}
@@ -199,7 +196,7 @@ abstract class ContainerType
foreach ($section['blocks'] as &$block) {
$block = $block_map[$block] ?? null;
}
- $section['blocks'] = array_filter($section['blocks']);
+ $section['blocks'] = array_values(array_filter($section['blocks']));
}
return $payload;
@@ -252,9 +249,9 @@ abstract class ContainerType
* It turns the classname into snakecase in order to find the
* template file in templates/courseware/container_types.
*
- * @return mixed the \Flexi_Template instance if exists, otherwise null.
+ * @return \Flexi\Template|null the \Flexi\Template instance if exists, otherwise null.
*/
- public function getPdfHtmlTemplate(): ?\Flexi_Template
+ public function getPdfHtmlTemplate(): ?\Flexi\Template
{
$template = null;
try {
diff --git a/lib/models/Courseware/ContainerTypes/ListContainer.php b/lib/models/Courseware/ContainerTypes/ListContainer.php
index b98d8a1..adbf7c3 100644
--- a/lib/models/Courseware/ContainerTypes/ListContainer.php
+++ b/lib/models/Courseware/ContainerTypes/ListContainer.php
@@ -2,8 +2,6 @@
namespace Courseware\ContainerTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware list container stored in payload.
*
@@ -50,10 +48,9 @@ class ListContainer extends ContainerType
$this->setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/ListContainer.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
}
diff --git a/lib/models/Courseware/ContainerTypes/TabsContainer.php b/lib/models/Courseware/ContainerTypes/TabsContainer.php
index 01f3d45..66a56b8 100644
--- a/lib/models/Courseware/ContainerTypes/TabsContainer.php
+++ b/lib/models/Courseware/ContainerTypes/TabsContainer.php
@@ -2,8 +2,6 @@
namespace Courseware\ContainerTypes;
-use Opis\JsonSchema\Schema;
-
/**
* This class represents the content of a Courseware tabs container stored in payload.
*
@@ -54,10 +52,9 @@ class TabsContainer extends ContainerType
$this->setPayload($payload);
}
- public static function getJsonSchema(): Schema
+ public static function getJsonSchema(): string
{
$schemaFile = __DIR__.'/TabsContainer.json';
-
- return Schema::fromJsonString(file_get_contents($schemaFile));
+ return file_get_contents($schemaFile);
}
}
diff --git a/lib/models/CronjobLog.class.php b/lib/models/CronjobLog.php
index c9e92f7..278a515 100644
--- a/lib/models/CronjobLog.class.php
+++ b/lib/models/CronjobLog.php
@@ -1,7 +1,7 @@
<?php
// +---------------------------------------------------------------------------+
// This file is part of Stud.IP
-// CronjobLog.class.php
+// CronjobLog.php
//
// Copyright (C) 2013 Jan-Hendrik Willms <tleilax+studip@gmail.com>
// +---------------------------------------------------------------------------+
diff --git a/lib/models/CronjobSchedule.class.php b/lib/models/CronjobSchedule.php
index 4304be1..08a18d3 100644
--- a/lib/models/CronjobSchedule.class.php
+++ b/lib/models/CronjobSchedule.php
@@ -1,7 +1,7 @@
<?php
// +---------------------------------------------------------------------------+
// This file is part of Stud.IP
-// CronjobSchedule.class.php
+// CronjobSchedule.php
//
// Copyright (C) 2013 Jan-Hendrik Willms <tleilax+studip@gmail.com>
// +---------------------------------------------------------------------------+
@@ -34,8 +34,6 @@
* @property string|null $title database column
* @property string|null $description database column
* @property string|null $parameters database column
- * @property string $priority database column
- * @property string $type database column
* @property int|null $minute database column
* @property int|null $hour database column
* @property int|null $day database column
@@ -53,10 +51,6 @@
class CronjobSchedule extends SimpleORMap
{
- const PRIORITY_LOW = 'low';
- const PRIORITY_NORMAL = 'normal';
- const PRIORITY_HIGH = 'high';
-
protected static function configure($config = [])
{
$config['db_table'] = 'cronjobs_schedules';
@@ -79,41 +73,6 @@ class CronjobSchedule extends SimpleORMap
}
/**
- * Returns a mapped version of the priorities (key = priority value,
- * value = localized priority label).
- *
- * @return Array The mapped priorities
- */
- public static function getPriorities()
- {
- $mapping = [];
- $mapping[self::PRIORITY_LOW] = _('niedrig');
- $mapping[self::PRIORITY_NORMAL] = _('normal');
- $mapping[self::PRIORITY_HIGH] = _('hoch');
-
- return $mapping;
- }
-
- /**
- * Maps a priority value to it's localized label.
- *
- * @param String $priority Priority value
- * @return String The localized label
- * @throws RuntimeException when an unknown priority value is passed
- */
- public static function describePriority($priority)
- {
- $priority = $priority ?? 'normal';
-
- $mapping = self::getPriorities();
- if (!isset($mapping[$priority])) {
- throw new RuntimeException('Access to unknown priority "' . $priority . '"');
- }
-
- return $mapping[$priority];
- }
-
- /**
* replaces title with task name if title is empty.
*
* @return string the title or the task name
@@ -171,10 +130,12 @@ class CronjobSchedule extends SimpleORMap
*
* @return CronjobSchedule Returns itself to allow chaining
*/
- public function activate()
+ public function activate(bool $run_immediately = false)
{
- $this->active = 1;
- $this->next_execution = $this->calculateNextExecution();
+ $next_execution = $run_immediately ? strtotime('-1 minute') : $this->calculateNextExecution();
+
+ $this->active = true;
+ $this->next_execution = $next_execution;
$this->store();
return $this;
@@ -187,7 +148,7 @@ class CronjobSchedule extends SimpleORMap
*/
public function deactivate()
{
- $this->active = 0;
+ $this->active = false;
$this->store();
return $this;
@@ -221,9 +182,6 @@ class CronjobSchedule extends SimpleORMap
$result = $this->task->engage($this->last_result, $this->parameters);
- if ($this->type === 'once') {
- $this->active = 0;
- }
$this->last_result = $result;
$this->store();
@@ -245,16 +203,12 @@ class CronjobSchedule extends SimpleORMap
/**
* Calculates the next execution for this schedule.
*
- * For schedules of type 'once' the check solely tests whether the
- * timestamp has already passed and will return false in that case.
- * Otherwise the defined timestamp will be returned.
- *
- * For schedules of type 'periodic' the next execution
- * is calculated by increasing the current timestamp and testing
- * whether all conditions match. This is not the best method to test
- * and should be optimized sooner or later.
+ * The next execution is calculated by increasing the current timestamp
+ * and testing whether all conditions match. This is not the best method
+ * to test and should be optimized sooner or later.
*
* @param mixed $now Defines the temporal fix point
+ *
* @return int Timestamp of calculated next execution
* @throws RuntimeException When calculation takes too long (you should
* check the conditions for validity in that case)
@@ -263,12 +217,6 @@ class CronjobSchedule extends SimpleORMap
{
$now = $now ?: time();
- if ($this->type === 'once') {
- return $now <= $this->next_execution
- ? $this->next_execution
- : false;
- }
-
$result = $now;
$result -= $result % 60;
diff --git a/lib/models/CronjobTask.class.php b/lib/models/CronjobTask.php
index f235951..1304bc1 100644
--- a/lib/models/CronjobTask.class.php
+++ b/lib/models/CronjobTask.php
@@ -1,7 +1,7 @@
<?php
// +---------------------------------------------------------------------------+
// This file is part of Stud.IP
-// CronjobSchedule.class.php
+// CronjobSchedule.php
//
// Copyright (C) 2013 Jan-Hendrik Willms <tleilax+studip@gmail.com>
// +---------------------------------------------------------------------------+
@@ -160,72 +160,70 @@ class CronjobTask extends SimpleORMap
// Convenience methods to ease the usage
/**
- * Schedules this task for a single execution at the provided time.
- *
- * @param int $timestamp When the task should be executed
- * @param String $priority Priority of the execution (low, normal, high),
- * defaults to normal
- * @param Array $parameters Optional parameters passed to the task
- * @return CronjobSchedule The generated schedule object.
- */
- public function scheduleOnce($timestamp, $priority = CronjobSchedule::PRIORITY_NORMAL,
- $parameters = [])
- {
- return CronjobScheduler::getInstance()->scheduleOnce(
- $this->id,
- $timestamp,
- $priority,
- $parameters
- );
- }
-
- /**
* Schedules this task for periodic execution with the provided schedule.
*
- * @param mixed $minute Minute part of the schedule:
+ * @param int|null $minute Minute part of the schedule:
* - null for "every minute" a.k.a. "don't care"
* - x < 0 for "every x minutes"
* - x >= 0 for "only at minute x"
- * @param mixed $hour Hour part of the schedule:
+ * @param int|null $hour Hour part of the schedule:
* - null for "every hour" a.k.a. "don't care"
* - x < 0 for "every x hours"
* - x >= 0 for "only at hour x"
- * @param mixed $day Day part of the schedule:
+ * @param int|null $day Day part of the schedule:
* - null for "every day" a.k.a. "don't care"
* - x < 0 for "every x days"
* - x > 0 for "only at day x"
- * @param mixed $month Month part of the schedule:
+ * @param int|null $month Month part of the schedule:
* - null for "every month" a.k.a. "don't care"
* - x < 0 for "every x months"
* - x > 0 for "only at month x"
- * @param mixed $day_of_week Day of week part of the schedule:
+ * @param int|null $day_of_week Day of week part of the schedule:
* - null for "every day" a.k.a. "don't care"
* - 1 >= x >= 7 for "exactly at day of week x"
* (x starts with monday at 1 and ends with
* sunday at 7)
- * @param String $priority Priority of the execution (low, normal, high),
- * defaults to normal
- * @param Array $parameters Optional parameters passed to the task
+ * @param array $parameters Optional parameters passed to the task
* @return CronjobSchedule The generated schedule object.
*/
- public function schedulePeriodic($minute = null, $hour = null,
- $day = null, $month = null, $day_of_week = null,
- $priority = CronjobSchedule::PRIORITY_NORMAL,
- $parameters = [])
- {
- return CronjobScheduler::getInstance()->schedulePeriodic(
+ public function schedule(
+ ?int $minute = null,
+ ?int $hour = null,
+ ?int $day = null,
+ ?int $month = null,
+ ?int $day_of_week = null,
+ array $parameters = []
+ ): CronjobSchedule {
+ return CronjobScheduler::getInstance()->schedule(
$this->id,
$minute,
$hour,
$day,
$month,
$day_of_week,
- $priority,
$parameters
);
}
/**
+ * An alias for schedule for backwards compatibility.
+ *
+ * @see CronjobTask::schedule()
+ * @return CronjobSchedule
+ */
+ public function schedulePeriodic(
+ $minute = null,
+ $hour = null,
+ $day = null,
+ $month = null,
+ $day_of_week = null,
+ $priority = '',
+ $parameters = []
+ ) {
+ return $this->schedule($minute, $hour, $day, $month, $day_of_week, $parameters);
+ }
+
+ /**
* Extracts the default parameter values from the associated task.
*
* @return array
diff --git a/lib/models/DataField.class.php b/lib/models/DataField.php
index 2d745a9..8a0bdb6 100644
--- a/lib/models/DataField.class.php
+++ b/lib/models/DataField.php
@@ -256,11 +256,8 @@ class DataField extends SimpleORMap implements PrivacyObject
* Specialized count method that returns the number of concrete entries.
*
* @return int number of entries
- *
- * @todo Add int return type when Stud.IP requires PHP8 minimal
*/
- #[ReturnTypeWillChange]
- public function count()
+ public function count(): int
{
return DatafieldEntryModel::countBySQL('datafield_id = ?', [$this->id]);
}
diff --git a/lib/models/DatafieldEntryModel.class.php b/lib/models/DatafieldEntryModel.php
index 33503e3..33503e3 100644
--- a/lib/models/DatafieldEntryModel.class.php
+++ b/lib/models/DatafieldEntryModel.php
diff --git a/lib/models/DatafieldEntryModelI18N.class.php b/lib/models/DatafieldEntryModelI18N.php
index aa93a63..aa93a63 100644
--- a/lib/models/DatafieldEntryModelI18N.class.php
+++ b/lib/models/DatafieldEntryModelI18N.php
diff --git a/lib/models/Degree.class.php b/lib/models/Degree.php
index 6fef834..9c908d3 100644
--- a/lib/models/Degree.class.php
+++ b/lib/models/Degree.php
@@ -1,6 +1,6 @@
<?php
/**
- * Degree.class.php
+ * Degree.php
* model class for table studiengang
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/Deputy.php b/lib/models/Deputy.php
index e2917e7..c74c741 100644
--- a/lib/models/Deputy.php
+++ b/lib/models/Deputy.php
@@ -1,6 +1,6 @@
<?php
/**
- * Deputy.class.php
+ * Deputy.php
* model class for table deputies
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/FileRef.php b/lib/models/FileRef.php
index c70d171..6bffbf3 100644
--- a/lib/models/FileRef.php
+++ b/lib/models/FileRef.php
@@ -86,9 +86,10 @@ class FileRef extends SimpleORMap implements PrivacyObject, FeedbackRange
public function cbLogDeleteFileRef()
{
StudipLog::log('FILE_DELETE',
- $this->id,
+ User::findCurrent()->id,
null,
sprintf(
+ 'Kommentar: %s',
$this->name
)
);
diff --git a/lib/models/Folder.php b/lib/models/Folder.php
index b2e8886..7b66621 100644
--- a/lib/models/Folder.php
+++ b/lib/models/Folder.php
@@ -97,9 +97,10 @@ class Folder extends SimpleORMap implements FeedbackRange
protected function cbLogDeleteFolder()
{
StudipLog::log('FOLDER_DELETE',
- $this->id,
+ User::findCurrent()->id,
null,
sprintf(
+ 'Kommentar: %s',
$this->name
)
);
diff --git a/lib/models/Freetext.php b/lib/models/Freetext.php
index 52182de..f241b5a 100644
--- a/lib/models/Freetext.php
+++ b/lib/models/Freetext.php
@@ -1,6 +1,6 @@
<?php
-require_once 'lib/classes/QuestionType.interface.php';
+require_once 'lib/classes/QuestionType.php';
/**
* @license GPL2 or any later version
@@ -65,12 +65,13 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
/**
* Returns the template of this question to answer the question.
- * @return Flexi_Template
- * @throws Flexi_TemplateNotFoundException if there is no template.
+ *
+ * @return Flexi\Template
+ * @throws Flexi\TemplateNotFoundException if there is no template.
*/
public function getDisplayTemplate()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__ . '/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__ . '/../../app/views'));
$template = $factory->open('questionnaire/question_types/freetext/freetext_answer.php');
$template->vote = $this;
return $template;
@@ -97,9 +98,11 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
/**
* Returns the template with the answers of the question so far.
+ *
* @param null $only_user_ids : array of user_ids
- * @return Flexi_Template
- * @throws Flexi_TemplateNotFoundException if there is no template.
+ *
+ * @return Flexi\Template
+ * @throws Flexi\TemplateNotFoundException if there is no template.
*/
public function getResultTemplate($only_user_ids = null)
{
@@ -111,7 +114,7 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
}
}
}
- $factory = new Flexi_TemplateFactory(realpath(__DIR__ . '/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__ . '/../../app/views'));
$template = $factory->open('questionnaire/question_types/freetext/freetext_evaluation.php');
$template->vote = $this;
$template->set_attribute('answers', $answers);
diff --git a/lib/models/Grading/Instance.php b/lib/models/Grading/Instance.php
index 14ab25a..7f362d3 100644
--- a/lib/models/Grading/Instance.php
+++ b/lib/models/Grading/Instance.php
@@ -66,4 +66,22 @@ class Instance extends \SimpleORMap
return self::findBySql('definition_id IN (?) AND user_id = ?', [$definitionIds, $user->id]);
}
+
+ /**
+ * setter for the rawgrade column. The database type is decimal(6,5) UNSIGNED, therefore
+ * the setter mimics the database behaviour to get valid results from ::isFieldDirty()
+ *
+ * @param mixed $grade
+ * @return string
+ */
+ public function setRawgrade($grade = 0): string
+ {
+ if ($grade < 0) {
+ $grade = 0;
+ }
+ if ($grade >= 10) {
+ $grade = 9.99999;
+ }
+ return $this->content['rawgrade'] = number_format($grade, 5, '.', '');
+ }
}
diff --git a/lib/models/HelpContent.class.php b/lib/models/HelpContent.php
index f1e61b1..e9a6f47 100644
--- a/lib/models/HelpContent.class.php
+++ b/lib/models/HelpContent.php
@@ -21,7 +21,7 @@
//require_once 'lib/object.inc.php';
/**
- * HelpContent.class.php - model class for Stud.IP help content
+ * HelpContent.php - model class for Stud.IP help content
*
* @author Arne Schröder <schroeder@data-quest>
* @access public
diff --git a/lib/models/HelpTour.class.php b/lib/models/HelpTour.php
index 68bd830..978e203 100644
--- a/lib/models/HelpTour.class.php
+++ b/lib/models/HelpTour.php
@@ -21,7 +21,7 @@
require_once 'lib/object.inc.php';
/**
- * HelpTour.class.php - model class for Stud.IP tours
+ * HelpTour.php - model class for Stud.IP tours
*
*
*
diff --git a/lib/models/HelpTourAudience.class.php b/lib/models/HelpTourAudience.php
index 6255a46..f341196 100644
--- a/lib/models/HelpTourAudience.class.php
+++ b/lib/models/HelpTourAudience.php
@@ -19,7 +19,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// +---------------------------------------------------------------------------+
/**
- * HelpTourSteps.class.php - model class for tour audiences
+ * HelpTourSteps.php - model class for tour audiences
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/HelpTourSettings.class.php b/lib/models/HelpTourSettings.php
index f24c86b..1cac957 100644
--- a/lib/models/HelpTourSettings.class.php
+++ b/lib/models/HelpTourSettings.php
@@ -19,7 +19,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// +---------------------------------------------------------------------------+
/**
- * HelpTourSteps.class.php - model class for tour steps
+ * HelpTourSteps.php - model class for tour steps
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/HelpTourStep.class.php b/lib/models/HelpTourStep.php
index 6f31326..3bd5ad8 100644
--- a/lib/models/HelpTourStep.class.php
+++ b/lib/models/HelpTourStep.php
@@ -19,7 +19,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// +---------------------------------------------------------------------------+
/**
- * HelpTourSteps.class.php - model class for tour steps
+ * HelpTourSteps.php - model class for tour steps
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -104,4 +104,3 @@ class HelpTourStep extends SimpleORMap
return true;
}
}
-
diff --git a/lib/models/HelpTourUser.class.php b/lib/models/HelpTourUser.php
index aa2869d..4992225 100644
--- a/lib/models/HelpTourUser.class.php
+++ b/lib/models/HelpTourUser.php
@@ -19,7 +19,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// +---------------------------------------------------------------------------+
/**
- * HelpTourUser.class.php - model class for tour user visits
+ * HelpTourUser.php - model class for tour user visits
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/Institute.class.php b/lib/models/Institute.php
index 47cf271..df344ff 100644
--- a/lib/models/Institute.class.php
+++ b/lib/models/Institute.php
@@ -1,6 +1,6 @@
<?php
/**
- * Institute.class.php - model class for table Institute
+ * Institute.php - model class for table Institute
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/InstituteMember.class.php b/lib/models/InstituteMember.php
index ec1c026..ec1c026 100644
--- a/lib/models/InstituteMember.class.php
+++ b/lib/models/InstituteMember.php
diff --git a/lib/models/InstitutePlanColumn.class.php b/lib/models/InstitutePlanColumn.php
index b5ec876..b5ec876 100644
--- a/lib/models/InstitutePlanColumn.class.php
+++ b/lib/models/InstitutePlanColumn.php
diff --git a/lib/models/Kategorie.class.php b/lib/models/Kategorie.php
index a43629f..a43629f 100644
--- a/lib/models/Kategorie.class.php
+++ b/lib/models/Kategorie.php
diff --git a/lib/models/LikertScale.php b/lib/models/LikertScale.php
index 8ac7823..3a055f3 100644
--- a/lib/models/LikertScale.php
+++ b/lib/models/LikertScale.php
@@ -1,6 +1,4 @@
<?php
-require_once 'lib/classes/QuestionType.interface.php';
-
/**
* @license GPL2 or any later version
*
@@ -53,7 +51,7 @@ class LikertScale extends QuestionnaireQuestion implements QuestionType
public function getDisplayTemplate()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/likert/likert_answer');
$template->set_attribute('vote', $this);
return $template;
@@ -73,7 +71,7 @@ class LikertScale extends QuestionnaireQuestion implements QuestionType
public function getUserIdsOfFilteredAnswer($answer_option)
{
$user_ids = [];
- list($statement_key, $options_key) = explode('_', $answer_option);
+ [$statement_key, $options_key] = explode('_', $answer_option);
foreach ($this->answers as $answer) {
$answerData = $answer['answerdata']->getArrayCopy();
if ($answerData['answers'][$statement_key] == $options_key) {
@@ -93,7 +91,7 @@ class LikertScale extends QuestionnaireQuestion implements QuestionType
}
}
}
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/likert/likert_evaluation');
$template->set_attribute('vote', $this);
$template->set_attribute('answers', $answers);
diff --git a/lib/models/LockRule.class.php b/lib/models/LockRule.php
index a3ef271..83dec60 100644
--- a/lib/models/LockRule.class.php
+++ b/lib/models/LockRule.php
@@ -1,6 +1,6 @@
<?php
/**
- * LockRule.class.php
+ * LockRule.php
* model class for table lock_rule
* this class represents one record of the lock_rules table
* the column attributes is converted to an ArrayObject and vice-versa,
diff --git a/lib/models/LoginBackground.class.php b/lib/models/LoginBackground.php
index 3ede275..530ae42 100644
--- a/lib/models/LoginBackground.class.php
+++ b/lib/models/LoginBackground.php
@@ -1,6 +1,6 @@
<?php
/**
- * LoginBackground.class.php
+ * LoginBackground.php
* model class for table loginbackgrounds
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/LoginFaq.class.php b/lib/models/LoginFaq.php
index d6cad40..4c049ac 100644
--- a/lib/models/LoginFaq.class.php
+++ b/lib/models/LoginFaq.php
@@ -1,6 +1,6 @@
<?php
/**
- * LoginFaq.class.php
+ * LoginFaq.php
* model class for table login_faq
*
*
diff --git a/lib/models/Lvgruppe.php b/lib/models/Lvgruppe.php
index 138d28e..05f3b59 100644
--- a/lib/models/Lvgruppe.php
+++ b/lib/models/Lvgruppe.php
@@ -232,7 +232,7 @@ class Lvgruppe extends ModuleManagementModelTreeItem
*
* @param string $term The search term.
* @param array|string $filter An array with filter options or a where part.
- * @return object A SimpleORMapCollection of LV-Gruppen.
+ * @return SimpleORMapCollection A SimpleORMapCollection of LV-Gruppen.
*/
public static function findBySearchTerm($term, $filter = null)
{
@@ -271,7 +271,7 @@ class Lvgruppe extends ModuleManagementModelTreeItem
* Retrieves all LV-Gruppen related to the Modulteil with given id.
*
* @param string $modulteil_id The id of a Modulteil.
- * @return object A SimpleORMapCollection of LV-Gruppen.
+ * @return SimpleORMapCollection A SimpleORMapCollection of LV-Gruppen.
*/
public static function findByModulteil($modulteil_id)
{
@@ -286,7 +286,7 @@ class Lvgruppe extends ModuleManagementModelTreeItem
* Retrieves all LV-Gruppen related to the course with given id.
*
* @param string $seminar_id The id of a course.
- * @return object A SimpleORMapCollection of LV-Gruppen.
+ * @return SimpleORMapCollection A SimpleORMapCollection of LV-Gruppen.
*/
public static function findBySeminar($seminar_id)
{
@@ -339,7 +339,7 @@ class Lvgruppe extends ModuleManagementModelTreeItem
/**
* Assigns the given course to the given LvGruppen.
*
- * @param array Array of ids
+ * @param string $seminar_id Array of ids
* @return int The number of assigned LvGruppen.
*/
public static function setLvgruppen($seminar_id, $lvgruppen_ids)
@@ -347,9 +347,13 @@ class Lvgruppe extends ModuleManagementModelTreeItem
$old = Lvgruppe::findBySeminar($seminar_id);
$removed = array_diff($old->pluck('id'), $lvgruppen_ids);
$added = array_diff($lvgruppen_ids, $old->pluck('id'));
+
+ $count_removed = 0;
foreach ($removed as $one) {
$count_removed += $old->findOneBy('id', $one)->removeSeminar($seminar_id);
}
+
+ $count_added = 0;
foreach ($added as $one) {
$count_added += Lvgruppe::get($one)->addSeminar($seminar_id);
}
diff --git a/lib/models/MailQueueEntry.class.php b/lib/models/MailQueueEntry.php
index bc956e7..d0f9685 100644
--- a/lib/models/MailQueueEntry.class.php
+++ b/lib/models/MailQueueEntry.php
@@ -104,7 +104,7 @@ class MailQueueEntry extends SimpleORMap
$status_messages[] = $status_message;
}, "tries = 0 " .
- "OR (last_try > (UNIX_TIMESTAMP() - 60 * 60) AND tries < 25) ORDER BY mkdate".
+ "OR (last_try > (UNIX_TIMESTAMP() - 60 * 60) AND tries < 25) ORDER BY tries, mkdate".
($limit > 0 ? " LIMIT ". (int) $limit : "")
);
diff --git a/lib/models/Message.class.php b/lib/models/Message.php
index 46493d6..fb6b78e 100644
--- a/lib/models/Message.class.php
+++ b/lib/models/Message.php
@@ -1,6 +1,6 @@
<?php
/**
- * Message.class.php
+ * Message.php
* model class for table message
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/MessageUser.class.php b/lib/models/MessageUser.php
index 0ae6dd5..1715de1 100644
--- a/lib/models/MessageUser.class.php
+++ b/lib/models/MessageUser.php
@@ -1,6 +1,6 @@
<?php
/**
- * MessageUser.class.php
+ * MessageUser.php
* model class for table message_user
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/MvvOverlappingConflict.class.php b/lib/models/MvvOverlappingConflict.php
index 6ac8e29..54b367f 100644
--- a/lib/models/MvvOverlappingConflict.class.php
+++ b/lib/models/MvvOverlappingConflict.php
@@ -1,6 +1,6 @@
<?php
/**
- * MvvOverlappingConflict.class.php - model class for table mvv_ovl_conflicts
+ * MvvOverlappingConflict.php - model class for table mvv_ovl_conflicts
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/MvvOverlappingExclude.php b/lib/models/MvvOverlappingExclude.php
index d199e30..6cde414 100644
--- a/lib/models/MvvOverlappingExclude.php
+++ b/lib/models/MvvOverlappingExclude.php
@@ -1,7 +1,7 @@
<?php
/**
- * MvvOverlappingExclude.class.php - model class for table mvv_ovl_excludes
+ * MvvOverlappingExclude.php - model class for table mvv_ovl_excludes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -46,4 +46,3 @@ class MvvOverlappingExclude extends SimpleORMap
}
}
-
diff --git a/lib/models/MvvOverlappingSelection.class.php b/lib/models/MvvOverlappingSelection.php
index 9d159e2..b3fcc15 100644
--- a/lib/models/MvvOverlappingSelection.class.php
+++ b/lib/models/MvvOverlappingSelection.php
@@ -1,6 +1,6 @@
<?php
/**
- * MvvOverlappingSelection.class.php - model class for table mvv_ovl_selections
+ * MvvOverlappingSelection.php - model class for table mvv_ovl_selections
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/NewsRange.class.php b/lib/models/NewsRange.php
index 7785214..675478f 100644
--- a/lib/models/NewsRange.class.php
+++ b/lib/models/NewsRange.php
@@ -1,6 +1,6 @@
<?php
/**
- * NewsRange.class.php - model class for table Institute
+ * NewsRange.php - model class for table Institute
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/NewsRoles.class.php b/lib/models/NewsRoles.php
index 56da6ec..28a4064 100644
--- a/lib/models/NewsRoles.class.php
+++ b/lib/models/NewsRoles.php
@@ -1,7 +1,7 @@
<?php
/**
- * NewsRoles.class.php - model class for the news roles
+ * NewsRoles.php - model class for the news roles
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/OERHostOERSI.php b/lib/models/OERHostOERSI.php
index 52e50d3..5e539bf 100644
--- a/lib/models/OERHostOERSI.php
+++ b/lib/models/OERHostOERSI.php
@@ -76,7 +76,7 @@ class OERHostOERSI extends OERHost
$material['difficulty_end'] = 12;
$material['uri'] = $material_data['_source']['id'];
$material['source_url'] = $material_data['_source']['id'];
- $material['content_type'] = $material_data['_source']['encoding'][0]['encodingFormat'] ?: '';
+ $material['content_type'] = $material_data['_source']['encoding'][0]['encodingFormat'] ?? '';
$material['license_identifier'] = $this->getLicenseID($material_data['_source']['license']['id']) ?: '';
if (!$material['category']) {
$material['category'] = $material->autoDetectCategory();
@@ -86,18 +86,23 @@ class OERHostOERSI extends OERHost
'front_image_url' => $material_data['_source']['image'] ?? null,
'download' => $material_data['_source']['encoding'][0]['contentUrl'] ?: '',
'id' => $material_data['_id'],
- 'organization' => $material_data['_source']['sourceOrganization'][0]['name'] ?: $material_data['_source']['publisher'][0]['name']
+ 'organization' => $material_data['_source']['sourceOrganization'][0]['name'] ?? $material_data['_source']['publisher'][0]['name'] ?? '',
];
$material->store();
//set users:
$userdata = [];
- foreach ((array) $material_data['_source']['creator'] as $creator) {
- $userdata[] = [
- 'user_id' => md5($creator['name']),
- 'name' => $creator['name'],
- 'host_url' => $this['url']
- ];
+ if (
+ isset($material_data['_source']['creator'])
+ && is_array($material_data['_source']['creator'])
+ ) {
+ foreach ($material_data['_source']['creator'] as $creator) {
+ $userdata[] = [
+ 'user_id' => md5($creator['name']),
+ 'name' => $creator['name'],
+ 'host_url' => $this['url']
+ ];
+ }
}
$material->setUsers($userdata);
diff --git a/lib/models/OERMaterial.php b/lib/models/OERMaterial.php
index 94559ef..604f845 100644
--- a/lib/models/OERMaterial.php
+++ b/lib/models/OERMaterial.php
@@ -164,7 +164,7 @@ class OERMaterial extends SimpleORMap
public static function fetchRemoteSearch($text, $tag = false)
{
$cache_name = "oer_remote_searched_for_".md5($text)."_".($tag ? 1 : 0);
- $already_searched = (bool) StudipCacheFactory::getCache()->read($cache_name);
+ $already_searched = (bool) \Studip\Cache\Factory::getCache()->read($cache_name);
if (!$already_searched) {
$hosts = OERHost::findBySQL("index_server = '1' AND allowed_as_index_server = '1' ORDER BY RAND()");
foreach ($hosts as $host) {
@@ -172,7 +172,7 @@ class OERMaterial extends SimpleORMap
$host->fetchRemoteSearch($text, $tag);
}
}
- StudipCacheFactory::getCache()->read($cache_name, "1", 60);
+ \Studip\Cache\Factory::getCache()->write($cache_name, "1", 60);
}
}
@@ -198,7 +198,7 @@ class OERMaterial extends SimpleORMap
return $output;
}
- $tf = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH']."/app/views");
+ $tf = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH']."/app/views");
if ($material->hasValidPreviewUrl() || $material->isPDF()) {
$template = $tf->open("oer/embed/url");
} elseif ($material->isVideo()) {
@@ -703,7 +703,7 @@ class OERMaterial extends SimpleORMap
$message = sprintf(
_('%1$s hat soeben neues Material auf dem OER Campus zur verfügung gestellt. Viel Spaß! <br> %2$s'),
$user_name,
- URLHelper::getURL("dispatch.php/oer/market/details/".$this->getId())
+ URLHelper::getURL("dispatch.php/oer/market/details/".$this->getId(), [], true)
);
URLHelper::setBaseURL($oldbase);
$messsaging->insert_message(
diff --git a/lib/models/OpenGraphURL.class.php b/lib/models/OpenGraphURL.php
index 29e5718..29e5718 100644
--- a/lib/models/OpenGraphURL.class.php
+++ b/lib/models/OpenGraphURL.php
diff --git a/lib/models/OpenGraphURLCollection.class.php b/lib/models/OpenGraphURLCollection.php
index f575945..f575945 100644
--- a/lib/models/OpenGraphURLCollection.class.php
+++ b/lib/models/OpenGraphURLCollection.php
diff --git a/lib/models/PersonalNotifications.class.php b/lib/models/PersonalNotifications.php
index 721038c..12d9c1b 100644
--- a/lib/models/PersonalNotifications.class.php
+++ b/lib/models/PersonalNotifications.php
@@ -262,7 +262,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function getCache($user_id)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cached = $cache->read($hash);
@@ -281,7 +281,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function setCache($user_id, $items)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cache->write($hash, serialize($items), self::CACHE_DURATION);
}
@@ -293,7 +293,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function expireCache($user_id)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cache->expire($hash);
}
diff --git a/lib/models/Questionnaire.php b/lib/models/Questionnaire.php
index f29a2de..777182d 100644
--- a/lib/models/Questionnaire.php
+++ b/lib/models/Questionnaire.php
@@ -129,7 +129,7 @@ class Questionnaire extends SimpleORMap implements PrivacyObject
return true;
} else {
//now look through all plugin if this assignment is related to plugin contents:
- foreach (PluginManager::getInstance()->getPlugins("QuestionnaireAssignmentPlugin") as $plugin) {
+ foreach (PluginManager::getInstance()->getPlugins(QuestionnaireAssignmentPlugin::class) as $plugin) {
if ($plugin->isQuestionnaireViewable($assignment)) {
return true;
}
@@ -172,7 +172,7 @@ class Questionnaire extends SimpleORMap implements PrivacyObject
return true;
} else {
//now look through all plugin if this assignment is related to plugin contents:
- foreach (PluginManager::getInstance()->getPlugins("QuestionnaireAssignmentPlugin") as $plugin) {
+ foreach (PluginManager::getInstance()->getPlugins(QuestionnaireAssignmentPlugin::class) as $plugin) {
if ($plugin->isQuestionnaireEditable($assignment)) {
return true;
}
diff --git a/lib/models/QuestionnaireInfo.php b/lib/models/QuestionnaireInfo.php
index fc6efc7..2bcf25d 100644
--- a/lib/models/QuestionnaireInfo.php
+++ b/lib/models/QuestionnaireInfo.php
@@ -50,7 +50,7 @@ class QuestionnaireInfo extends QuestionnaireQuestion implements QuestionType
public function getDisplayTemplate()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/info/info');
$template->set_attribute('vote', $this);
return $template;
@@ -68,7 +68,7 @@ class QuestionnaireInfo extends QuestionnaireQuestion implements QuestionType
public function getResultTemplate($only_user_ids = null)
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/info/info');
$template->set_attribute('vote', $this);
return $template;
diff --git a/lib/models/RangeScale.php b/lib/models/RangeScale.php
index 78bc65b..20e134a 100644
--- a/lib/models/RangeScale.php
+++ b/lib/models/RangeScale.php
@@ -1,6 +1,4 @@
<?php
-require_once 'lib/classes/QuestionType.interface.php';
-
/**
* @license GPL2 or any later version
*
@@ -20,7 +18,7 @@ class RangeScale extends QuestionnaireQuestion implements QuestionType
{
public static function getIcon(bool $active = false) : Icon
{
- return Icon::create(static::getIconShape(), $active ? 'clickable' : 'info');
+ return Icon::create(static::getIconShape(), $active ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO);
}
/**
@@ -53,7 +51,7 @@ class RangeScale extends QuestionnaireQuestion implements QuestionType
public function getDisplayTemplate()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/rangescale/rangescale_answer');
$template->set_attribute('vote', $this);
return $template;
@@ -64,7 +62,11 @@ class RangeScale extends QuestionnaireQuestion implements QuestionType
$answer = $this->getMyAnswer();
$answers = Request::getArray('answers');
- $userAnswer = (array) $answers[$this->getId()]['answerdata']['answers'];
+ if (!empty($answers[$this->getId()])) {
+ $userAnswer = (array)$answers[$this->getId()]['answerdata']['answers'];
+ } else {
+ $userAnswer = [];
+ }
$answer->setData(['answerdata' => ['answers' => $userAnswer ] ]);
return $answer;
}
@@ -72,7 +74,7 @@ class RangeScale extends QuestionnaireQuestion implements QuestionType
public function getUserIdsOfFilteredAnswer($answer_option)
{
$user_ids = [];
- list($statement_key, $options_key) = explode('_', $answer_option);
+ [$statement_key, $options_key] = explode('_', $answer_option);
foreach ($this->answers as $answer) {
$answerData = $answer['answerdata']->getArrayCopy();
if ($answerData['answers'][$statement_key] == $options_key) {
@@ -92,7 +94,7 @@ class RangeScale extends QuestionnaireQuestion implements QuestionType
}
}
}
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/rangescale/rangescale_evaluation');
$template->set_attribute('vote', $this);
$template->set_attribute('answers', $answers);
diff --git a/lib/models/Semester.class.php b/lib/models/Semester.php
index 4eefa3b..ef3246b 100644
--- a/lib/models/Semester.class.php
+++ b/lib/models/Semester.php
@@ -1,7 +1,7 @@
<?php
/**
- * Semester.class.php
+ * Semester.php
* model class for table semester_data
*
* This program is free software; you can redistribute it and/or
@@ -181,7 +181,7 @@ class Semester extends SimpleORMap
if (!is_array(self::$semester_cache) || $force_reload) {
self::$semester_cache = [];
if (!$force_reload) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$semester_data_array = unserialize($cache->read('DB_SEMESTER_DATA'));
if ($semester_data_array) {
foreach ($semester_data_array as $semester_data) {
@@ -202,7 +202,7 @@ class Semester extends SimpleORMap
}
$semester_data[] = $semester->toRawArray();
}
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write('DB_SEMESTER_DATA', serialize($semester_data));
}
}
@@ -471,7 +471,7 @@ class Semester extends SimpleORMap
*/
public function refreshCache()
{
- StudipCacheFactory::getCache()->expire('DB_SEMESTER_DATA');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEMESTER_DATA');
}
/*
diff --git a/lib/models/SemesterCourse.class.php b/lib/models/SemesterCourse.php
index 04590e3..79e5230 100644
--- a/lib/models/SemesterCourse.class.php
+++ b/lib/models/SemesterCourse.php
@@ -1,6 +1,6 @@
<?php
/**
- * SemesterCourse.class.php
+ * SemesterCourse.php
* Contains the SemesterCourse model.
*
* This class represents entries in the mapping table
diff --git a/lib/models/SemesterHoliday.class.php b/lib/models/SemesterHoliday.php
index 90f9ecd..265f8e1 100644
--- a/lib/models/SemesterHoliday.class.php
+++ b/lib/models/SemesterHoliday.php
@@ -1,6 +1,6 @@
<?php
/**
- * SemesterHoliday.class.php
+ * SemesterHoliday.php
* model class for table semester_holiday
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/SeminarCycleDate.class.php b/lib/models/SeminarCycleDate.php
index f384426..b8431a3 100644
--- a/lib/models/SeminarCycleDate.class.php
+++ b/lib/models/SeminarCycleDate.php
@@ -6,7 +6,7 @@ require_once 'lib/dates.inc.php';
/**
- * SeminarCycleDate.class.php
+ * SeminarCycleDate.php
* model class for table seminar_cycle_dates
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/SimpleCollection.class.php b/lib/models/SimpleCollection.class.php
deleted file mode 100644
index 4d77682..0000000
--- a/lib/models/SimpleCollection.class.php
+++ /dev/null
@@ -1,788 +0,0 @@
-<?php
-if (!defined('SORT_NATURAL')) {
- define('SORT_NATURAL', 6);
-}
-if (!defined('SORT_FLAG_CASE')) {
- define('SORT_FLAG_CASE', 8);
-}
-
-/**
- * SimpleCollection.class.php
- * collection of assoc arrays with convenience
- *
- * 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 André Noack <noack@data-quest.de>
- * @copyright 2013 Stud.IP Core-Group
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- *
- * @template T
- */
-class SimpleCollection extends StudipArrayObject
-{
- /**
- * callable to initialize collection
- *
- * @var ?callable(): array<T>
- */
- protected $finder;
-
- /**
- * number of records after last init
- *
- * @var int
- */
- protected $last_count;
-
- /**
- * collection with deleted records
- * @var static
- */
- protected $deleted;
-
- /**
- * creates a collection from an array of arrays
- * all arrays should contain same keys, but is not enforced
- *
- * @param array<T> $data array containing assoc arrays
- * @return SimpleCollection<T>
- */
- public static function createFromArray(array $data)
- {
- return new self($data);
- }
-
- /**
- * converts arrays or objects to ArrayObject objects
- * if ArrayAccess interface is not available
- *
- * @param mixed $a
- * @return StudipArrayObject|ArrayAccess
- */
- public static function arrayToArrayObject($a)
- {
- if ($a instanceof StudipArrayObject) {
- $a->setFlags(StudipArrayObject::ARRAY_AS_PROPS);
- return $a;
- }
-
- if ($a instanceof ArrayObject) {
- return new StudipArrayObject($a->getArrayCopy(), StudipArrayObject::ARRAY_AS_PROPS);
- }
-
- if ($a instanceof ArrayAccess) {
- return $a;
- }
-
- return new StudipArrayObject((array) $a, StudipArrayObject::ARRAY_AS_PROPS);
- }
-
- /**
- * returns closure to compare a value against given arguments
- * using given operator
- *
- * @param string|callable(mixed, mixed|array): bool $operator
- * @param mixed|array $args
- * @throws InvalidArgumentException
- * @return callable(mixed): bool comparison function
- */
- public static function getCompFunc($operator, $args)
- {
- if (is_callable($operator)) {
- $comp_func = function ($a) use ($args, $operator) {
- return $operator($a, $args);
- };
- } else {
- if (!is_array($args)) {
- $args = [$args];
- }
- switch ($operator) {
- case '==':
- $comp_func = function ($a) use ($args) {
- return in_array($a, $args);
- };
- break;
- case '===':
- $comp_func = function ($a) use ($args) {
- return in_array($a, $args, true);
- };
- break;
- case '!=':
- case '<>':
- $comp_func = function ($a) use ($args) {
- return !in_array($a, $args);
- };
- break;
- case '!==':
- $comp_func = function ($a) use ($args) {
- return !in_array($a, $args, true);
- };
- break;
- case '<':
- case '>':
- case '<=':
- case '>=':
- $op_func = function ($a, $b) use ($operator) {
- if ($operator === '<') {
- return $a < $b;
- } elseif ($operator === '<=') {
- return $a <= $b;
- } elseif ($operator === '>=') {
- return $a >= $b;
- } elseif ($operator === '>') {
- return $a > $b;
- }
- };
- $comp_func = function ($a) use ($op_func, $args) {
- return $op_func($a, $args[0]);
- };
- break;
- case '><':
- $comp_func = function ($a) use ($args) {
- return $a > $args[0] && $a < $args[1];
- };
- break;
- case '>=<=':
- $comp_func = function ($a) use ($args) {
- return $a >= $args[0] && $a <= $args[1];
- };
- break;
- case '%=':
- $comp_func = function ($a) use ($args) {
- $a = mb_strtolower(static::translitLatin1($a));
- $args = array_map([static::class, 'translitLatin1'], $args);
- $args = array_map('mb_strtolower', $args);
- return in_array($a, $args);
- };
- break;
- case '*=':
- $comp_func = function ($a) use ($args) {
- foreach ($args as $arg) {
- if (mb_strpos($a, $arg) !== false) {
- return true;
- }
- }
- return false;
- };
- break;
- case '^=':
- $comp_func = function ($a) use ($args) {
- foreach ($args as $arg) {
- if (mb_strpos($a, $arg) === 0) {
- return true;
- }
- }
- return false;
- };
- break;
- case '$=':
- $comp_func = function ($a) use ($args) {
- foreach ($args as $arg) {
- $found = mb_strrpos($a, $arg);
- if ($found !== false && ($found + mb_strlen($arg)) === mb_strlen($a)) {
- return true;
- }
- }
- return false;
- };
- break;
- case '~=':
- $comp_func = function ($a) use ($args) {
- foreach ($args as $arg) {
- if (preg_match($arg, $a) === 1) {
- return true;
- }
- }
- return false;
- };
- break;
- default:
- throw new InvalidArgumentException('unknown operator: ' . $operator);
- }
- }
- return $comp_func;
- }
-
- /**
- * transliterates latin1 string to ascii
- *
- * @param string $text
- * @return string
- */
- public static function translitLatin1($text)
- {
- if (!preg_match('/[\200-\377]/', $text)) {
- return $text;
- }
- $text = str_replace(['ä','Ä','ö','Ö','ü','Ü','ß'], ['a','A','o','O','u','U','s'], $text);
- $text = str_replace(['À','Á','Â','Ã','Å','Æ'], 'A' , $text);
- $text = str_replace(['à','á','â','ã','å','æ'], 'a' , $text);
- $text = str_replace(['È','É','Ê','Ë'], 'E' , $text);
- $text = str_replace(['è','é','ê','ë'], 'e' , $text);
- $text = str_replace(['Ì','Í','Î','Ï'], 'I' , $text);
- $text = str_replace(['ì','í','î','ï'], 'i' , $text);
- $text = str_replace(['Ò','Ó','Õ','Ô','Ø'], 'O' , $text);
- $text = str_replace(['ò','ó','ô','õ','ø'], 'o' , $text);
- $text = str_replace(['Ù','Ú','Û'], 'U' , $text);
- $text = str_replace(['ù','ú','û'], 'u' , $text);
- $text = str_replace(['Ç','ç','Ð','Ñ','Ý','ñ','ý','ÿ'], ['C','c','D','N','Y','n','y','y'] , $text);
- return $text;
- }
-
- /**
- * Constructor
- *
- * @param array<T>|callable(): array<T> $data array or closure to fill collection
- */
- public function __construct($data = [])
- {
- parent::__construct();
- $this->finder = is_callable($data) ? $data : null;
- $this->deleted = clone $this;
- if (is_callable($data)) {
- $this->refresh();
- } else {
- $this->exchangeArray($data);
- }
- }
-
- /**
- * @param array $input
- * @return array
- */
- public function exchangeArray($input)
- {
- return parent::exchangeArray(array_map(
- [static::class, 'arrayToArrayObject'],
- $input
- ));
- }
-
- /**
- * converts the object and all elements to plain arrays
- *
- * @return array
- */
- public function toArray()
- {
- $args = func_get_args();
- return $this->map(function ($a) use ($args) {
- if (method_exists($a, 'toArray')) {
- return call_user_func_array([$a, 'toArray'], $args);
- }
- if (method_exists($a, 'getArrayCopy')) {
- return $a->getArrayCopy();
- }
- return (array) $a;
- }
- );
- }
-
- /**
- *
- * @see ArrayObject::append()
- */
- public function append($newval)
- {
- parent::append(static::arrayToArrayObject($newval));
- }
-
- /**
- * Sets the value at the specified index
- * ensures the value has ArrayAccess
- *
- * @param mixed $index
- * @param mixed $newval
- *
- * @see ArrayObject::offsetSet()
- * @return void
- *
- * @todo Add void return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetSet($index, $newval)
- {
- if (is_numeric($index)) {
- $index = (int) $index;
- }
- parent::offsetSet($index, static::arrayToArrayObject($newval));
- }
-
- /**
- * Unsets the value at the specified index
- * value is moved to internal deleted collection
- *
- * @see ArrayObject::offsetUnset()
- * @throws InvalidArgumentException
- *
- * @todo Add void return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetUnset($index)
- {
- if ($this->offsetExists($index)) {
- $this->deleted[] = $this->offsetGet($index);
- }
- parent::offsetUnset($index);
- }
-
- /**
- * sets the finder function
- *
- * @param callable(): array<T> $finder
- * @return void
- */
- public function setFinder(callable $finder)
- {
- $this->finder = $finder;
- }
-
- /**
- * get deleted records collection
- * @return SimpleCollection<T>
- */
- public function getDeleted()
- {
- return $this->deleted;
- }
-
- /**
- * reloads the elements of the collection
- * by calling the finder function
- *
- * @return ?int of records after refresh
- */
- public function refresh()
- {
- if (is_callable($this->finder)) {
- $data = call_user_func($this->finder);
- $this->exchangeArray($data);
- $this->deleted->exchangeArray([]);
- return $this->last_count = $this->count();
- }
- }
-
- /**
- * returns a new collection containing all elements
- * where given columns value matches given value(s) using passed operator
- * pass array for multiple values
- *
- * operators:
- * == equal, like php
- * === identical, like php
- * !=,<> not equal, like php
- * !== not identical, like php
- * <,>,<=,>= less,greater,less or equal,greater or equal
- * >< between without borders, needs two arguments
- * >=<= between including borders, needs two arguments
- * %= like string, transliterate to ascii,case insensitive
- * *= contains string
- * ^= begins with string
- * $= ends with string
- * ~= regex
- *
- * @param string $key the column name
- * @param mixed $values value to search for
- * @param string|callable $op operator to find
- * @return SimpleCollection<T> with found records
- */
- public function findBy($key, $values, $op = '==')
- {
- $comp_func = self::getCompFunc($op, $values);
- return $this->filter(function ($record) use ($comp_func, $key) {
- return $comp_func($record[$key]);
- });
- }
-
- /**
- * returns the first element
- * where given column has given value(s)
- * pass array for multiple values
- *
- * @param string $key the column name
- * @param mixed $values value to search for,
- * @param string|callable $op operator to find
- * @return ?T found record
- */
- public function findOneBy($key, $values, $op = '==')
- {
- $comp_func = self::getCompFunc($op, $values);
- return $this->filter(function ($record) use ($comp_func, $key) {
- return $comp_func($record[$key]);
- }, 1)->first();
- }
-
- /**
- * apply given callback to all elements of
- * collection
- *
- * @param callable(T): int $func the function to call
- * @return int|false addition of return values
- */
- public function each(callable $func)
- {
- $result = false;
- foreach ($this->storage as $record) {
- $result += call_user_func($func, $record);
- }
- return $result;
- }
-
- /**
- * apply given callback to all elements of
- * collection and give back array of return values
- *
- * @param callable(T, mixed): mixed $func the function to call
- * @return array<mixed>
- */
- public function map(callable $func)
- {
- $results = [];
- foreach ($this->storage as $key => $value) {
- $results[$key] = call_user_func($func, $value, $key);
- }
- return $results;
- }
-
- /**
- * filter elements
- * if given callback returns true
- *
- * @param ?callable(T, mixed): bool $func the function to call
- * @param ?integer $limit limit number of found records
- * @return SimpleCollection<T> containing filtered elements
- */
- public function filter(callable $func = null, $limit = null)
- {
- $results = [];
- $found = 0;
- foreach ($this->storage as $key => $value) {
- if (call_user_func($func, $value, $key)) {
- $results[$key] = $value;
- if ($limit && (++$found == $limit)) {
- break;
- }
- }
- }
- return self::createFromArray($results);
- }
-
- /**
- * Returns whether any element of the collection returns true for the
- * given callback.
- *
- * @param callable(T, mixed): bool $func the function to call
- * @return bool
- */
- public function any(callable $func)
- {
- foreach ($this->storage as $key => $value) {
- if (call_user_func($func, $value, $key)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether every element of the collection returns true for the
- * given callback.
- *
- * @param callable(T, mixed): bool $func the function to call
- * @return bool
- */
- public function every(callable $func)
- {
- foreach ($this->storage as $key => $value) {
- if (!call_user_func($func, $value, $key)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * extract array of columns values
- * pass array or space-delimited string for multiple columns
- *
- * @param string|array $columns the column(s) to extract
- * @return array of extracted values
- */
- public function pluck($columns)
- {
- if (!is_array($columns)) {
- $columns = words($columns);
- }
- $func = function ($r) use ($columns) {
- $result = [];
- foreach ($columns as $c) {
- $result[] = $r[$c];
- }
- return $result;
- };
- $result = $this->map($func);
- return count($columns) === 1 ? array_map('current', $result) : $result;
- }
-
- /**
- * returns the collection as grouped array
- * first param is the column to group by, it becomes the key in
- * the resulting array, default is pk. Limit returned fields with second param
- * The grouped entries can optoionally go through the given
- * callback. If no callback is provided, only the first grouped
- * entry is returned, suitable for grouping by unique column
- *
- * @param string $group_by the column to group by, pk if ommitted
- * @param string|array|null $only_these_fields limit returned fields
- * @param ?callable $group_func closure to aggregate grouped entries
- * @return array assoc array
- */
- public function toGroupedArray($group_by = 'id', $only_these_fields = null, callable $group_func = null)
- {
- $result = [];
- if (is_string($only_these_fields)) {
- $only_these_fields = words($only_these_fields);
- }
- foreach ($this->toArray() as $record) {
- $key = $record[$group_by];
- $ret = [];
- if (is_array($only_these_fields)) {
- $result[$key][] = array_intersect_key($record, array_flip($only_these_fields));
- } else {
- $result[$key][] = $record;
- }
- }
- if ($group_func === null) {
- $group_func = 'current';
- }
- return array_map($group_func, $result);
- }
-
- /**
- * get the first element
- *
- * @return ?T first element or null
- */
- public function first()
- {
- $keys = array_keys($this->storage);
- $first_offset = reset($keys);
- return $this->offsetGet($first_offset ?: 0);
- }
-
- /**
- * get the last element
- *
- * @return ?T last element or null
- */
- public function last()
- {
- $keys = array_keys($this->storage);
- $last_offset = end($keys);
- return $this->offsetGet($last_offset ?: 0);
- }
-
- /**
- * get the the value from given key from first element
- *
- * @param string $key
- * @return mixed
- */
- public function val($key)
- {
- $first = $this->first();
- return $first[$key] ?? null;
- }
-
- /**
- * mark element(s) for deletion
- * where given column has given value(s)
- * element(s) are moved to
- * internal deleted collection
- * pass array for multiple values
- *
- * operators:
- * == equal, like php
- * === identical, like php
- * !=,<> not equal, like php
- * !== not identical, like php
- * <,>,<=,>= less,greater,less or equal,greater or equal
- * >< between without borders, needs two arguments
- * >=<= between including borders, needs two arguments
- * %= like string, transliterate to ascii,case insensitive
- * *= contains string
- * ^= begins with string
- * $= ends with string
- * ~= regex
- *
- * @param string $key
- * @param mixed $values
- * @param string|callable(mixed, mixed|array): bool $op operator to find elements
- * @return int|false number of unsetted elements
- */
- public function unsetBy($key, $values, $op = '==')
- {
- $ret = false;
- $comp_func = self::getCompFunc($op, $values);
- foreach ($this->storage as $k => $record) {
- if ($comp_func($record[$key])) {
- $this->offsetunset($k);
- $ret += 1;
- }
- }
- return $ret;
- }
-
- /**
- * sorts the collection by columns of contained elements and returns it
- *
- * works like sql order by:
- * first param is a string containing combinations of column names
- * and sort direction, separated by comma e.g.
- * 'name asc, nummer desc '
- * sorts first by name ascending and then by nummer descending
- * second param denotes the sort type (using PHP sort constants):
- * SORT_LOCALE_STRING:
- * compare items as strings, transliterate latin1 to ascii, case insensitiv, natural order for numbers
- * SORT_NUMERIC:
- * compare items as integers
- * SORT_STRING:
- * compare items as strings
- * SORT_NATURAL:
- * compare items as strings using "natural ordering"
- * SORT_FLAG_CASE:
- * can be combined (bitwise OR) with SORT_STRING or SORT_NATURAL to sort strings case-insensitively
- *
- * @param string $order columns to order by
- * @param integer $sort_flags
- * @return $this the sorted collection
- */
- public function orderBy($order, $sort_flags = SORT_LOCALE_STRING)
- {
- //('name asc, nummer desc ')
- $sort_locale = false;
- switch ($sort_flags) {
- case SORT_NATURAL:
- $sort_func = 'strnatcmp';
- break;
- case SORT_NATURAL | SORT_FLAG_CASE:
- $sort_func = 'strnatcasecmp';
- break;
- case SORT_STRING | SORT_FLAG_CASE:
- $sort_func = 'strcasecmp';
- break;
- case SORT_STRING:
- $sort_func = 'strcmp';
- break;
- case SORT_NUMERIC:
- $sort_func = function ($a, $b) {
- return (int) $a - (int) $b;
- };
- break;
- case SORT_LOCALE_STRING:
- default:
- $sort_func = 'strnatcasecmp';
- $sort_locale = true;
- }
-
- $sorter = [];
- foreach (explode(',', $order) as $one) {
- $sorter[] = array_values(array_filter(array_map('trim', explode(' ', $one))));
- }
-
- $func = function ($d1, $d2) use ($sorter, $sort_func, $sort_locale) {
- do {
- $current_sorter = current($sorter);
- $field = $current_sorter[0];
- $dir = $current_sorter[1] ?? '';
- if (!$sort_locale) {
- $value1 = $d1[$field];
- $value2 = $d2[$field];
- } else {
- $value1 = static::translitLatin1(mb_substr($d1[$field], 0, 100));
- $value2 = static::translitLatin1(mb_substr($d2[$field], 0, 100));
- }
- $ret = $sort_func($value1, $value2);
- if (strtolower($dir) == 'desc') $ret = $ret * -1;
- } while ($ret === 0 && next($sorter));
-
- return $ret;
- };
- if (count($sorter)) {
- $this->uasort($func);
- }
- return $this;
- }
-
- /**
- * returns a new collection contaning a sequence of original collection
- * mimics the sql limit constrain:
- * used with one parameter, the first x elements are extracted
- * used with two parameters, the first parameter denotes the offset, the second the
- * number of elements
- *
- * @param integer $arg1
- * @param ?integer $arg2
- * @return SimpleCollection<T>
- */
- public function limit($arg1, $arg2 = null)
- {
- if (is_null($arg2)) {
- if ($arg1 > 0) {
- $row_count = $arg1;
- $offset = 0;
- } else {
- $row_count = abs($arg1);
- $offset = $arg1;
- }
- } else {
- $offset = $arg1;
- $row_count = $arg2;
- }
- return self::createFromArray(array_slice($this->storage, $offset, $row_count, true));
- }
-
- /**
- * calls the given method on all elements
- * of the collection
- * @param literal-string $method methodname to call
- * @param array $params parameters for methodcall
- * @return array of all return values
- */
- public function sendMessage($method, $params = []) {
- $results = [];
- foreach ($this->storage as $record) {
- $results[] = call_user_func_array([$record, $method], $params);
- }
- return $results;
- }
-
- /**
- * magic version of sendMessage
- * calls undefineds methods on all elements of the collection
- * But beware of the dark side...
- *
- * @param literal-string $method methodname to call
- * @param array $params parameters for methodcall
- * @return array of all return values
- */
- public function __call($method, $params)
- {
- return $this->sendMessage($method, $params);
- }
-
- /**
- * merge in another collection, elements are appended
- *
- * @param SimpleCollection<T> $a_collection
- * @return void
- */
- public function merge(SimpleCollection $a_collection)
- {
- $this->storage = array_merge($this->storage, $a_collection->getArrayCopy());
- }
-}
diff --git a/lib/models/SimpleORMap.class.php b/lib/models/SimpleORMap.class.php
deleted file mode 100644
index 4a0caa3..0000000
--- a/lib/models/SimpleORMap.class.php
+++ /dev/null
@@ -1,2501 +0,0 @@
-<?php
-/**
- * SimpleORMap.class.php
- * simple object-relational mapping
- *
- * 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 André Noack <noack@data-quest.de>
- * @copyright 2010 Stud.IP Core-Group
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
-*/
-
-class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
-{
- /**
- * Defines `_` as character used when joining composite primary keys.
- */
- const ID_SEPARATOR = '_';
-
- /**
- * table row data
- * @var array $content
- */
- protected $content = [];
-
- /**
- * table row data
- * @var array $content_db
- */
- protected $content_db = [];
-
- /**
- * new state of entry
- * @var boolean $is_new
- */
- protected $is_new = true;
-
- /**
- * deleted state of entry
- * @var boolean $is_deleted
- */
- protected $is_deleted = false;
-
- /**
- * db table metadata
- * @var ?array $schemes;
- */
- public static $schemes = null;
-
- /**
- * configuration data for subclasses
- * @see self::configure()
- * @var array $config;
- */
- protected static $config = [];
-
- /**
- * stores instantiated related objects
- * @var array $relations
- */
- protected $relations = [];
-
- /**
- * assoc array for storing values for additional fields
- *
- * @var array $additional_data
- */
- protected $additional_data = [];
-
- /**
- * reserved indentifiers, fields with those names must not have an explicit getXXX() method
- * @var array $reserved_slots
- */
- protected static $reserved_slots = ['value','newid','iterator','tablemetadata', 'relationvalue','wherequery','relationoptions','data','new','id'];
-
- /**
- * indicator for batch operations in findEachBySQL
- *
- * @var bool $performs_batch_operation
- */
- protected static $performs_batch_operation = false;
-
- /**
- * name of db table
- * @return string
- */
- protected static function db_table()
- {
- return static::config('db_table');
- }
-
- /**
- * table columns
- * @return array
- */
- protected static function db_fields()
- {
- return static::config('db_fields');
- }
-
- /**
- * primary key columns
- * @return array
- */
- protected static function pk()
- {
- return static::config('pk');
- }
-
- /**
- * default values for columns
- * @return array
- */
- protected static function default_values()
- {
- return static::config('default_values');
- }
-
- /**
- * list of columns to deserialize
- * @return array key is name of column, value is name of ArrayObject class
- */
- protected static function serialized_fields()
- {
- return static::config('serialized_fields');
- }
-
- /**
- * aliases for columns
- * alias => column
- * @return array
- */
- protected static function alias_fields()
- {
- return static::config('alias_fields');
- }
-
- /**
- * multi-language fields
- * name => boolean
- * @return array
- */
- protected static function i18n_fields()
- {
- return static::config('i18n_fields');
- }
-
- /**
- * additional computed fields
- * name => callable
- * @return array
- */
- protected static function additional_fields()
- {
- return static::config('additional_fields');
- }
-
- /**
- * 1:n relation
- * @return array
- */
- protected static function has_many()
- {
- return static::config('has_many');
- }
-
- /**
- * 1:1 relation
- * @return array
- */
- protected static function has_one()
- {
- return static::config('has_one');
- }
-
- /**
- * n:1 relations
- * @return array
- */
- protected static function belongs_to()
- {
- return static::config('belongs_to');
- }
-
- /**
- * n:m relations
- * @return array
- */
- protected static function has_and_belongs_to_many()
- {
- return static::config('has_and_belongs_to_many');
- }
-
- /**
- * callbacks
- * @return array<string, array<string|Closure>>
- */
- protected static function registered_callbacks()
- {
- return static::config('registered_callbacks');
- }
-
- /**
- * contains an array of all used identifiers for fields
- * (db columns + aliased columns + additional columns + relations)
- * @return array
- */
- protected static function known_slots()
- {
- return static::config('known_slots');
- }
-
- /**
- * assoc array used to map SORM callback to NotificationCenter
- * keys are SORM callbacks, values notifications
- * eg. 'after_create' => 'FooDidCreate'
- *
- * @return array
- */
- protected static function notification_map()
- {
- return static::config('notification_map');
- }
-
- /**
- * assoc array for mapping get/set Methods
- *
- * @return array
- */
- protected static function getter_setter_map()
- {
- return static::config('getter_setter_map');
- }
-
- //////////////////////////////////////////////////
-
- /**
- * set configuration data from subclass
- *
- * @param ?array $config configuration data
- * @return void
- */
- protected static function configure($config = [])
- {
- $class = get_called_class();
-
- if (empty($config['db_table'])) {
- $config['db_table'] = strtolower($class);
- }
-
- if (!isset($config['db_fields'])) {
- if (static::tableScheme($config['db_table'])) {
- $config['db_fields'] = self::$schemes[$config['db_table']]['db_fields'];
- $config['pk'] = self::$schemes[$config['db_table']]['pk'];
- }
- }
-
- if (isset($config['pk'])
- && !isset($config['db_fields']['id'])
- && !isset($config['alias_fields']['id'])
- && !isset($config['additional_fields']['id'])
- ) {
- if (count($config['pk']) === 1) {
- $config['alias_fields']['id'] = $config['pk'][0];
- } else {
- $config['additional_fields']['id'] = ['get' => '_getId',
- 'set' => '_setId'];
- }
- }
- if (isset($config['additional_fields'])) {
- foreach ($config['additional_fields'] as $a_field => $a_config) {
- if (is_array($a_config) && !(isset($a_config['get']) || isset($a_config['set']))) {
- $relation = $a_config[0] ?? '';
- $relation_field = $a_config[1] ?? '';
- if (!$relation) {
- list($relation, $relation_field) = explode('_', $a_field);
- }
- if (!$relation_field || !$relation) {
- throw new UnexpectedValueException('no relation found for autoget/set additional field: ' . $a_field);
- }
- $config['additional_fields'][$a_field] = ['get' => '_getAdditionalValueFromRelation',
- 'set' => '_setAdditionalValue',
- 'relation' => $relation,
- 'relation_field' => $relation_field];
- }
- }
- }
- if (isset($config['serialized_fields'])) {
- foreach ($config['serialized_fields'] as $a_field => $object_type) {
- if (!(is_subclass_of($object_type, 'StudipArrayObject'))) {
- throw new UnexpectedValueException(sprintf('serialized field %s must use subclass of StudipArrayObject', $a_field));
- }
- }
- }
-
- foreach (['default_values', 'serialized_fields', 'alias_fields', 'i18n_fields', 'additional_fields'] as $fields) {
- if (!isset($config[$fields])) {
- $config[$fields] = [];
- }
- }
-
- foreach (['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) {
- if (isset($config[$type]) && is_array($config[$type])) {
- foreach (array_keys($config[$type]) as $one) {
- $config['relations'][$one] = null;
- }
- } else {
- $config[$type] = [];
- }
- }
-
- $callbacks = ['before_create',
- 'before_update',
- 'before_store',
- 'before_delete',
- 'before_initialize',
- 'after_create',
- 'after_update',
- 'after_store',
- 'after_delete',
- 'after_initialize'];
-
- foreach ($callbacks as $callback) {
- if (!isset($config['registered_callbacks'][$callback])) {
- $config['registered_callbacks'][$callback] = [];
- }
- }
-
- $auto_notification_map['after_create'] = $class . 'DidCreate';
- $auto_notification_map['after_store'] = $class . 'DidStore';
- $auto_notification_map['after_delete'] = $class . 'DidDelete';
- $auto_notification_map['after_update'] = $class . 'DidUpdate';
- $auto_notification_map['before_create'] = $class . 'WillCreate';
- $auto_notification_map['before_store'] = $class . 'WillStore';
- $auto_notification_map['before_delete'] = $class . 'WillDelete';
- $auto_notification_map['before_update'] = $class . 'WillUpdate';
-
- foreach ($auto_notification_map as $cb => $notification) {
- if (isset($config['notification_map'][$cb])) {
- if (strpos($config['notification_map'][$cb], $notification) !== false) {
- $config['notification_map'][$cb] .= ' ' . $notification;
- }
- } else {
- $config['notification_map'][$cb] = $notification;
- }
- }
-
- if (is_array($config['notification_map'])) {
- foreach (array_keys($config['notification_map']) as $cb) {
- $config['registered_callbacks'][$cb][] = 'cbNotificationMapper';
- }
- }
-
- if (!I18N::isEnabled() || empty($config['i18n_fields'])) {
- $config['i18n_fields'] = [];
- } elseif (is_string($config['i18n_fields'])) {
- $i18n_fields = words($config['i18n_fields']);
- $config['i18n_fields'] = array_combine(
- $i18n_fields,
- array_fill(0, count($i18n_fields), true)
- );
- } elseif (array_is_list($config['i18n_fields'])) {
- $config['i18n_fields'] = array_combine(
- $config['i18n_fields'],
- array_fill(0, count($config['i18n_fields']), true)
- );
- }
-
- array_unshift($config['registered_callbacks']['after_initialize'], 'cbAfterInitialize');
-
- $config['known_slots'] = array_merge(
- array_keys($config['db_fields']),
- array_keys($config['alias_fields'] ?? []),
- array_keys($config['additional_fields'] ?? []),
- array_keys($config['relations'] ?? [])
- );
-
- foreach (array_map('strtolower', get_class_methods($class)) as $method) {
- if (in_array(substr($method, 0, 3), ['get', 'set'])) {
- $verb = substr($method, 0, 3);
- $name = substr($method, 3);
- if (in_array($name, $config['known_slots']) && !in_array($name, static::$reserved_slots) && !isset($config['additional_fields'][$name][$verb])) {
- $config['getter_setter_map'][$name][$verb] = $method;
- }
- }
- }
- self::$config[$class] = $config;
- }
-
- /**
- * fetch config data for the called class
- *
- * @param string $key config key
- * @return mixed value of config key (null if not set)
- */
- protected static function config($key)
- {
- if (!array_key_exists(static::class, self::$config)) {
- static::configure();
- }
-
- return self::$config[static::class][$key] ?? null;
- }
-
- /**
- * fetch table metadata from db or from local cache
- *
- * @param string $db_table
- * @return bool true if metadata could be fetched
- */
- public static function tableScheme($db_table)
- {
- if (self::$schemes === null) {
- $cache = StudipCacheFactory::getCache();
- self::$schemes = unserialize($cache->read('DB_TABLE_SCHEMES'));
- }
- if (!isset(self::$schemes[$db_table])) {
- $db = DBManager::get()->query("SHOW COLUMNS FROM $db_table");
- while($rs = $db->fetch(PDO::FETCH_ASSOC)){
- $db_fields[strtolower($rs['Field'])] = [
- 'name' => $rs['Field'],
- 'null' => $rs['Null'],
- 'default' => $rs['Default'],
- 'type' => $rs['Type'],
- 'extra' => $rs['Extra']
- ];
- if ($rs['Key'] == 'PRI'){
- $pk[] = strtolower($rs['Field']);
- }
- }
- self::$schemes[$db_table]['db_fields'] = $db_fields;
- self::$schemes[$db_table]['pk'] = $pk;
- $cache = StudipCacheFactory::getCache();
- $cache->write('DB_TABLE_SCHEMES', serialize(self::$schemes));
- }
- return isset(self::$schemes[$db_table]);
- }
-
- /**
- * force reload of cached table metadata
- * @return void
- */
- public static function expireTableScheme()
- {
- StudipCacheFactory::getCache()->expire('DB_TABLE_SCHEMES');
- self::$schemes = null;
- self::$config = [];
- }
-
- /**
- * Returns new instance for given key when found in the database, else null.
- *
- * @param string $id primary key
- * @return static|null
- */
- public static function find($id)
- {
- $class = get_called_class();
- $ref = new ReflectionClass($class);
- /** @var static $record */
- $record = $ref->newInstanceArgs(func_get_args());
- if (!$record->isNew()) {
- return $record;
- } else {
- return null;
- }
- }
-
- /**
- * Returns true if given key exists in the database.
- *
- * @param string|array $id primary key
- * @return boolean
- */
- public static function exists($id)
- {
- $ret = false;
- $db_table = static::db_table();
- $class = get_called_class();
- $record = new $class();
- call_user_func_array([$record, 'setId'], func_get_args());
- $where_query = $record->getWhereQuery();
- if ($where_query) {
- $query = "SELECT 1 FROM `$db_table` WHERE "
- . join(" AND ", $where_query);
- $ret = (bool)DBManager::get()->query($query)->fetchColumn();
- }
- return $ret;
- }
-
- /**
- * returns number of records
- *
- * @param ?string $sql sql clause to use on the right side of WHERE
- * @param ?array $params params for query
- * @return int
- */
- public static function countBySql($sql = '1', $params = [])
- {
- $db_table = static::db_table();
- $db = DBManager::get();
- $has_join = stripos($sql, 'JOIN ');
- if ($has_join === false || $has_join > 10) {
- $sql = 'WHERE ' . $sql;
- }
- $sql = "SELECT count(*) FROM `" . $db_table . "` " . $sql;
- $st = $db->prepare($sql);
- $st->execute($params);
- return (int)$st->fetchColumn();
- }
-
- /**
- * creates new record with given data in db
- * returns the new object or null
- * @param array $data assoc array of record
- * @return ?static
- */
- public static function create($data)
- {
- $class = get_called_class();
- $record = new $class();
- $record->setData($data, false);
- if ($record->store()) {
- return $record;
- } else {
- return null;
- }
- }
-
- /**
- * build object with given data
- *
- * @param array $data assoc array of record
- * @param ?bool $is_new set object to new state
- * @return static
- */
- public static function build($data, $is_new = true)
- {
- $class = get_called_class();
- /** @var static $record */
- $record = new $class();
- $record->setData($data, !$is_new);
- $record->setNew($is_new);
- return $record;
- }
-
- /**
- * build object with given data and mark it as existing
- *
- * @param array $data assoc array of record
- * @return static
- */
- public static function buildExisting($data)
- {
- return static::build($data, false);
- }
-
- /**
- * generate SimpleORMap object structure from assoc array
- * if given array contains data of related objects in sub-arrays
- * they are also generated. Existing records are updated, new records are created
- * (but changes are not yet stored)
- *
- * @param array $data
- * @return static
- */
- public static function import($data)
- {
- $class = get_called_class();
- $record_data = [];
- $relation_data = [];
- foreach ($data as $key => $value) {
- if (is_array($value)) {
- $relation_data[$key] = $value;
- } else {
- $record_data[$key] = $value;
- }
- }
- $record = static::toObject($record_data);
- if (!$record instanceof $class) {
- $record = new $class();
- $record->setData($record_data, true);
- } else {
- $record->setData($record_data);
- }
- if (is_array($relation_data)) {
- foreach ($relation_data as $relation => $data) {
- $options = $record->getRelationOptions($relation);
- if ($options['type'] == 'has_one') {
- $record->{$relation} = call_user_func([$options['class_name'], 'import'], $data);
- }
- if ($options['type'] == 'has_many' || $options['type'] == 'has_and_belongs_to_many') {
- foreach ($data as $one) {
- $current = call_user_func([$options['class_name'], 'import'], $one);
- if ($options['type'] == 'has_many') {
- $foreign_key_value = call_user_func($options['assoc_func_params_func'], $record);
- call_user_func($options['assoc_foreign_key_setter'], $current, $foreign_key_value);
- }
- if ($current->id !== null) {
- $existing = $record->{$relation}->find($current->id);
- if ($existing) {
- $existing->setData($current);
- } else {
- $record->{$relation}->append($current);
- }
- } else {
- $record->{$relation}->append($current);
- }
- }
- }
- }
- }
- return $record;
- }
-
- /**
- * returns array of instances of given class filtered by given sql
- * @param string $sql sql clause to use on the right side of WHERE
- * @param ?array $params parameters for query
- * @return static[] array of "self" objects
- */
- public static function findBySQL($sql, $params = [])
- {
- $db_table = static::db_table();
-
- $has_join = stripos($sql, 'JOIN ');
- if ($has_join === false || $has_join > 10) {
- $sql = 'WHERE ' . $sql;
- }
- $sql = "SELECT `" . $db_table . "`.* FROM `" . $db_table . "` " . $sql;
- $stmt = DBManager::get()->prepare($sql);
- $stmt->execute($params);
-
- $record = static::build([], false);
-
- $ret = [];
- do {
- $clone = clone $record;
- $clone->setNew(false);
- $stmt->setFetchMode(PDO::FETCH_INTO, $clone);
-
- if ($clone = $stmt->fetch()) {
- $clone->applyCallbacks('after_initialize');
- $ret[] = $clone;
- }
- } while ($clone);
- return $ret;
- }
-
- /**
- * returns one instance of given class filtered by given sql
- * only first row of query is used
- * @param string $where sql clause to use on the right side of WHERE
- * @param ?array $params parameters for query
- * @return ?static
- */
- public static function findOneBySQL($where, $params = [])
- {
- if (stripos($where, 'LIMIT') === false) {
- $where .= " LIMIT 1";
- }
- $found = static::findBySQL($where, $params);
- return isset($found[0]) ? $found[0] : null;
- }
-
- /**
- * find related records for a n:m relation (has_many_and_belongs_to_many)
- * using a combination table holding the keys
- *
- * @param string $foreign_key_value value of foreign key to find related records
- * @param array $options relation options from other side of relation
- * @return static[] array of "self" objects
- */
- public static function findThru($foreign_key_value, $options)
- {
- $thru_table = $options['thru_table'];
- $thru_key = $options['thru_key'];
- $thru_assoc_key = $options['thru_assoc_key'];
- $assoc_foreign_key = $options['assoc_foreign_key'];
-
- $db_table = static::db_table();
-
- $sql = "SELECT `$db_table`.* FROM `$thru_table`
- INNER JOIN `$db_table` ON `$thru_table`.`$thru_assoc_key` = `$db_table`.`$assoc_foreign_key`
- WHERE `$thru_table`.`$thru_key` = ? " . ($options['order_by'] ?? '');
- $st = DBManager::get()->prepare($sql);
- $st->execute([$foreign_key_value]);
-
- $record = static::build([], false);
-
- $ret = [];
- do {
- $clone = clone $record;
- $clone->setNew(false);
- $st->setFetchMode(PDO::FETCH_INTO, $clone);
-
- if ($clone = $st->fetch()) {
- $clone->applyCallbacks('after_initialize');
- $ret[] = $clone;
- }
- } while ($clone);
- return $ret;
- }
-
- /**
- * passes objects for given sql through given callback
- *
- * @param callable $callable callback which gets the current record as param
- * @param string $sql where clause of sql
- * @param ?array $params sql statement parameters
- * @return integer number of found records
- */
- public static function findEachBySQL($callable, $sql, $params = [])
- {
- $has_join = stripos($sql, 'JOIN ');
- if ($has_join === false || $has_join > 10) {
- $sql = "WHERE {$sql}";
- }
-
- $db_table = static::db_table();
- $st = DBManager::get()->prepare("SELECT `{$db_table}`.* FROM `{$db_table}` {$sql}");
- $st->execute($params);
-
- // Indicate that we are performing a batch operation
- static::$performs_batch_operation = true;
-
- $record = static::build([], false);
-
- $ret = 0;
- do {
- $clone = clone $record;
- $clone->setNew(false);
- $st->setFetchMode(PDO::FETCH_INTO, $clone);
-
- if ($clone = $st->fetch()) {
- $clone->applyCallbacks('after_initialize');
- $callable($clone, $ret++);
- }
- } while ($clone);
-
- // Reset batch operation indicator
- static::$performs_batch_operation = false;
-
- return $ret;
- }
-
- /**
- * returns array of instances of given class for by given pks
- * @param ?array $pks array of primary keys
- * @param ?string $order order by clause
- * @param ?array $order_params
- * @return static[]
- */
- public static function findMany($pks = [], $order = '', $order_params = [])
- {
- $db_table = static::db_table();
- $pk = static::pk();
- $db = DBManager::get();
- if (count($pk) > 1) {
- throw new Exception('not implemented yet');
- }
- $where = "`$db_table`.`{$pk[0]}` IN (" . $db->quote($pks) . ") ";
- return static::findBySQL($where . $order, $order_params);
- }
-
- /**
- * passes objects for by given pks through given callback
- *
- * @param callable $callable callback which gets the current record as param
- * @param ?array $pks array of primary keys of called class
- * @param ?string $order order by sql
- * @param ?array $order_params
- * @return integer number of found records
- */
- public static function findEachMany($callable, $pks = [], $order = '', $order_params = [])
- {
- $db_table = static::db_table();
- $pk = static::pk();
- $db = DBManager::get();
- if (count($pk) > 1) {
- throw new Exception('not implemented yet');
- }
- $where = "`$db_table`.`{$pk[0]}` IN (" . $db->quote($pks) . ") ";
- return static::findEachBySQL($callable, $where . $order, $order_params);
- }
-
- /**
- * passes objects for given sql through given callback
- * and returns an array of callback return values
- *
- * @param callable $callable callback which gets the current record as param
- * @param string $where where clause of sql
- * @param array $params sql statement parameters
- * @return array return values of callback
- */
- public static function findAndMapBySQL($callable, $where, $params = [])
- {
- $ret = [];
- $calleach = function($m) use (&$ret, $callable) {
- $ret[] = $callable($m);
- };
- static::findEachBySQL($calleach, $where, $params);
- return $ret;
- }
-
- /**
- * passes objects for by given pks through given callback
- * and returns an array of callback return values
- *
- * @param callable $callable callback which gets the current record as param
- * @param ?array $pks array of primary keys of called class
- * @param ?string $order order by sql
- * @param ?array $order_params
- * @return array return values of callback
- */
- public static function findAndMapMany($callable, $pks = [], $order = '', $order_params = [])
- {
- $ret = [];
- $calleach = function($m) use (&$ret, $callable) {
- $ret[] = $callable($m);
- };
- $db_table = static::db_table();
- $pk = static::pk();
- $db = DBManager::get();
- if (count($pk) > 1) {
- throw new Exception('not implemented yet');
- }
- $where = "`$db_table`.`{$pk[0]}` IN (" . $db->quote($pks) . ") ";
- static::findEachBySQL($calleach, $where . $order, $order_params);
- return $ret;
- }
-
- /**
- * deletes objects specified by sql clause
- * @param string $where sql clause to use on the right side of WHERE
- * @param ?array $params parameters for query
- * @return integer number of deleted records
- */
- public static function deleteBySQL($where, $params = [])
- {
- $killeach = function($record) {$record->delete();};
- return static::findEachBySQL($killeach, $where, $params);
- }
-
- /**
- * returns object of given class for given id or null
- * the param could be a string, an assoc array containing primary key field
- * or an already matching object. In all these cases an object is returned
- *
- * @param string|static|array $id_or_object id as string, object or assoc array
- * @return static
- */
- public static function toObject($id_or_object)
- {
- $class = get_called_class();
- if ($id_or_object instanceof $class) {
- return $id_or_object;
- }
- if (is_array($id_or_object)) {
- $pk = static::pk();
- $key_values = [];
- foreach ($pk as $key) {
- if (array_key_exists($key, $id_or_object)) {
- $key_values[] = $id_or_object[$key];
- }
- }
- if (count($pk) === count($key_values)) {
- if (count($pk) === 1) {
- $id = $key_values[0];
- } else {
- $id = $key_values;
- }
- } else {
- $id = null;
- }
- } else {
- $id = $id_or_object;
- }
- return call_user_func([$class, 'find'], $id);
- }
-
- /**
- * interceptor for static findByColumn / findEachByColumn / countByColumn /
- * deleteByColumn magic
- * @param string $name
- * @param array $arguments
- * @throws BadMethodCallException
- * @return int|static|static[]
- */
- public static function __callStatic($name, $arguments)
- {
- $db_table = static::db_table();
- $alias_fields = static::alias_fields();
- $db_fields = static::db_fields();
- $name = strtolower($name);
- $class = get_called_class();
- $order = '';
- $param_arr = [];
- $where = '';
- $where_param = is_array($arguments[0]) ? $arguments[0] : [$arguments[0]];
- $prefix = strstr($name, 'by', true);
- $field = substr($name, strlen($prefix) + 2);
- switch ($prefix) {
- case 'findone':
- $order = $arguments[1] ?? '';
- $param_arr[0] =& $where;
- $param_arr[1] = [$where_param];
- $method = 'findonebysql';
- break;
- case 'find':
- case 'findmany':
- $order = $arguments[1] ?? '';
- $param_arr[0] =& $where;
- $param_arr[1] = [$where_param];
- $method = 'findbysql';
- break;
- case 'findeach':
- case 'findeachmany':
- $order = $arguments[2] ?? '';
- $param_arr[0] = $arguments[0];
- $param_arr[1] =& $where;
- $param_arr[2] = [$arguments[1]];
- $method = 'findeachbysql';
- break;
- case 'count':
- case 'delete':
- $param_arr[0] =& $where;
- $param_arr[1] = [$where_param];
- $method = "{$prefix}bysql";
- break;
- default:
- throw new BadMethodCallException("Method $class::$name not found");
- }
- if (isset($alias_fields[$field])) {
- $field = $alias_fields[$field];
- }
- if (isset($db_fields[$field])) {
- $where = "`$db_table`.`$field` IN(?) " . $order;
- return call_user_func_array([$class, $method], $param_arr);
- }
- throw new BadMethodCallException("Method $class::$name not found");
- }
-
- /**
- * constructor, give primary key of record as param to fetch
- * corresponding record from db if available, if not preset primary key
- * with given value. Give null to create new record
- *
- * @param null|int|string|array $id primary key of table
- */
- function __construct($id = null)
- {
- foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) {
- foreach (array_keys($this->$type()) as $one) {
- $this->relations[$one] = null;
- }
- }
-
- if ($id) {
- $this->setId($id);
- }
- $this->restore();
- }
-
- /**
- * returns internal used id value (multiple keys concatenated with _)
- * @param mixed $field unused parameter
- * @return ?string
- */
- protected function _getId($field)
- {
- return is_null($this->getId())
- ? null
- : implode(self::ID_SEPARATOR, $this->getId());
- }
-
- /**
- * sets internal used id value (multiple keys concatenated with _)
- * @param string $field Field to set (unused since it's always the id)
- * @param string $value Value for id field
- * @return bool
- */
- protected function _setId($field, $value)
- {
- return $this->setId(explode(self::ID_SEPARATOR, $value));
- }
-
- /**
- * retrieves an additional field value from relation
- *
- * @param string $field
- * @return mixed
- */
- protected function _getAdditionalValueFromRelation($field)
- {
- list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'],
- $this->additional_fields()[$field]['relation_field']];
- if (!array_key_exists($field, $this->additional_data)) {
- $this->_setAdditionalValue($field, $this->getRelationValue($relation, $relation_field));
- }
- return $this->additional_data[$field];
- }
-
- /**
- * sets additional value in field imported from relation
- *
- * @param string $field
- * @param mixed $value
- * @return mixed
- */
- protected function _setAdditionalValueFromRelation($field, $value)
- {
- list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'],
- $this->additional_fields()[$field]['relation_field']];
- $this->$relation->$field = $value;
- unset($this->additional_data[$field]);
- return $this->_getAdditionalValueFromRelation($field);
- }
-
- /**
- * @param string $field
- * @return mixed
- */
- protected function _getAdditionalValue($field)
- {
- return $this->additional_data[$field];
- }
-
- /**
- * @param string $field
- * @param mixed $value
- * @return mixed
- */
- protected function _setAdditionalValue($field, $value)
- {
- return $this->additional_data[$field] = $value;
- }
-
- /**
- * clean up references after cloning
- * @return void
- */
- function __clone()
- {
- $this->setNew(true);
- //all references link still to old object => reset all aliases
- foreach ($this->alias_fields() as $alias => $field) {
- if (isset($this->db_fields()[$field])) {
- $content_value = $this->content[$field];
- $content_db_value = $this->content_db[$field];
- unset($this->content[$alias]);
- unset($this->content_db[$alias]);
- unset($this->content[$field]);
- unset($this->content_db[$field]);
- if (is_object($content_value)) {
- $this->content[$field] = clone $content_value;
- } else {
- $this->content[$field] = $content_value;
- }
- if (is_object($content_db_value)) {
- $this->content_db[$field] = clone $content_db_value;
- } else {
- $this->content_db[$field] = $content_db_value;
- }
- }
- }
- foreach ($this->alias_fields() as $alias => $field) {
- if (isset($this->db_fields()[$field])) {
- $this->content[$alias] =& $this->content[$field];
- $this->content_db[$alias] =& $this->content_db[$field];
- }
- }
- //unset all relations for now
- //TODO: maybe a deep copy of all belonging objects is more appropriate
- foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) {
- foreach (array_keys($this->$type()) as $one) {
- $this->relations[$one] = null;
- }
- }
- //begun the clone war has... hmpf
- }
-
- /**
- * try to determine all needed options for a relationship from
- * configured options
- *
- * @param string $type
- * @param string $name
- * @param array $options
- * @throws Exception if options for thru_table could not be determined
- * @return array
- */
- protected function parseRelationOptions($type, $name, $options)
- {
- if (empty($options['class_name'])) {
- throw new Exception('Option class_name not set for relation ' . $name);
- }
- if (empty($options['assoc_foreign_key'])) {
- if ($type === 'has_many' || $type === 'has_one') {
- $options['assoc_foreign_key'] = $this->pk()[0];
- } else if ($type === 'belongs_to') {
- $options['assoc_foreign_key'] = 'id';
- }
- }
- if ($type === 'has_and_belongs_to_many') {
- $thru_table = $options['thru_table'];
- if (empty($options['thru_key'])) {
- $options['thru_key'] = $this->pk()[0];
- }
- if (empty($options['thru_assoc_key']) || empty($options['assoc_foreign_key'])) {
- $class = $options['class_name'];
- $record = new $class();
- $meta = $record->getTableMetadata();
- if (empty($options['thru_assoc_key'])) {
- $options['thru_assoc_key'] = $meta['pk'][0];
- }
- if (empty($options['assoc_foreign_key'])) {
- $options['assoc_foreign_key']= $meta['pk'][0];
- }
- }
- static::tableScheme($thru_table);
- if (is_array(self::$schemes[$thru_table])) {
- $thru_key_ok = isset(self::$schemes[$thru_table]['db_fields'][$options['thru_key']]);
- $thru_assoc_key_ok = isset(self::$schemes[$thru_table]['db_fields'][$options['thru_assoc_key']]);
- }
- if (!$thru_assoc_key_ok || !$thru_key_ok) {
- throw new Exception("Could not determine keys for relation " . $name . " through table " . $thru_table);
- }
- if ($options['assoc_foreign_key'] instanceof Closure) {
- throw new Exception("For relation " . $name . " assoc_foreign_key must be a name of a column");
- }
- }
- if (empty($options['assoc_func'])) {
- if ($type !== 'has_and_belongs_to_many') {
- $options['assoc_func'] = $options['assoc_foreign_key'] === 'id' ? 'find' : 'findBy' . $options['assoc_foreign_key'];
- } else {
- $options['assoc_func'] = 'findThru';
- }
- }
- if (empty($options['foreign_key'])) {
- $options['foreign_key'] = 'id';
- }
- if (isset($options['foreign_key']) && $options['foreign_key'] instanceof Closure) {
- $options['assoc_func_params_func'] = function($record) use ($name, $options) { return call_user_func($options['foreign_key'], $record, $name, $options);};
- } else {
- $options['assoc_func_params_func'] = function($record) use ($name, $options) { return $options['foreign_key'] === 'id' ? $record->getId() : $record->getValue($options['foreign_key']);};
- }
- if (isset($options['assoc_foreign_key']) && $options['assoc_foreign_key'] instanceof Closure) {
- if ($type === 'belongs_to') {
- $options['assoc_foreign_key_getter'] = function($record, $that) use ($name, $options) { return call_user_func($options['assoc_foreign_key'], $record, $name, $options, $that);};
- } else {
- $options['assoc_foreign_key_setter'] = function($record, $params) use ($name, $options) { return call_user_func($options['assoc_foreign_key'], $record, $params, $name, $options);};
- }
- } elseif (!empty($options['assoc_foreign_key'])) {
- if ($type === 'belongs_to') {
- $options['assoc_foreign_key_getter'] = function($record, $that) use ($name, $options) { return $record->getValue($options['assoc_foreign_key']);};
- } else {
- $options['assoc_foreign_key_setter'] = function($record, $value) use ($name, $options) { return $record->setValue($options['assoc_foreign_key'], $value);};
- }
- } else {
- throw new Exception("Could not determine assoc_foreign_key for relation " . $name);
- }
- return $options;
- }
-
- /**
- * returns array with option for given relation
- * available options:
- * 'type': relation type, on of 'has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'
- * 'class_name': name of class for related records
- * 'foreign_key': name of column with foreign key
- * or callback to retrieve foreign key value
- * 'assoc_foreign_key': name of foreign key column in related class
- * 'assoc_func': name of static method to call on related class to find related records
- * 'assoc_func_params_func': callback to retrieve params for assoc_func
- * 'thru_table': name of relation table for n:m relation
- * 'thru_key': name of column holding foreign key in relation table
- * 'thru_assoc_key': name of column holding foreign key from related class in relation table
- * 'on_delete': contains simply 'delete' to indicate that related records should be deleted
- * or callback to invoke before record gets deleted
- * 'on_store': contains simply 'store' to indicate that related records should be stored
- * or callback to invoke after record gets stored
- *
- * @param string $relation name of relation
- * @return array assoc array containing options
- */
- function getRelationOptions($relation)
- {
- $options = [];
- foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) {
- if (isset($this->$type()[$relation])) {
- $options = self::$config[get_class($this)][$type][$relation];
- if (!isset($options['type'])) {
- $options = $this->parseRelationOptions($type, $relation, $options, $this->db_table());
- $options['type'] = $type;
- self::$config[get_class($this)][$type][$relation] = $options;
- }
- break;
- }
- }
- return $options;
- }
-
- /**
- * returns table and columns metadata
- *
- * @return array assoc array with columns, primary keys and name of table
- */
- function getTableMetadata()
- {
- return ['fields' => $this->db_fields(),
- 'pk' => $this->pk(),
- 'table' => $this->db_table(),
- 'additional_fields' => $this->additional_fields(),
- 'alias_fields' => $this->alias_fields(),
- 'relations' => array_keys($this->relations)];
- }
-
- /**
- * returns true, if table has an auto_increment column
- *
- * @return boolean
- */
- function hasAutoIncrementColumn()
- {
- return $this->db_fields()[$this->pk()[0]]['extra'] == 'auto_increment';
- }
-
- /**
- * set primary key for entry, combined keys must be passed as array
- * @param int|string|array $id primary key
- * @throws InvalidArgumentException if given key is not complete
- * @return boolean
- */
- public function setId($id)
- {
- if (!is_array($id)){
- $id = [$id];
- }
- if (count($this->pk()) != count($id)){
- throw new InvalidArgumentException("Invalid ID, Primary Key {$this->db_table()} is " .join(",",$this->pk()));
- } else {
- foreach ($this->pk() as $count => $key){
- $this->content[$key] = $id[$count];
- }
- return true;
- }
- }
-
- /**
- * returns primary key, multiple keys as array
- * @return null|string|array current primary key, null if not set
- */
- function getId()
- {
- if (count($this->pk()) == 1) {
- return $this->content[$this->pk()[0]] ?? null;
- } else {
- $id = [];
- foreach ($this->pk() as $key) {
- if (array_key_exists($key, $this->content)) {
- $id[] = $this->content[$key];
- }
- }
- return (count($this->pk()) == count($id) ? $id : null);
- }
- }
-
- /**
- * create new unique pk as md5 hash
- * if pk consists of multiple columns, false is returned
- * @return boolean|string
- */
- function getNewId()
- {
- $id = false;
- if (count($this->pk()) == 1) {
- do {
- $id = md5(uniqid($this->db_table(), 1));
- $db = DBManager::get()->query("SELECT `{$this->pk()[0]}` FROM `{$this->db_table()}` "
- . "WHERE `{$this->pk()[0]}` = '$id'");
- } while($db->fetch());
- }
- return $id;
- }
-
- /**
- * returns data of table row as assoc array
- * pass array of fieldnames or ws separated string to limit
- * fields
- *
- * @param null|array|string $only_these_fields limit returned fields
- * @return array
- */
- function toArray($only_these_fields = null)
- {
- $ret = [];
- if (is_string($only_these_fields)) {
- $only_these_fields = words($only_these_fields);
- }
- $fields = array_diff($this->known_slots(), array_keys($this->relations));
- if (is_array($only_these_fields)) {
- $only_these_fields = array_filter(array_map(function($s) {
- return is_string($s) ? strtolower($s) : null;
- }, $only_these_fields));
- $fields = array_intersect($only_these_fields, $fields);
- }
- foreach ($fields as $field) {
- $ret[$field] = $this->getValue($field);
- if ($ret[$field] instanceof StudipArrayObject) {
- $ret[$field] = $ret[$field]->getArrayCopy();
- }
- }
- return $ret;
- }
-
- /**
- * Returns data of table row as assoc array with raw contents like
- * they are in the database.
- * Pass array of fieldnames or ws separated string to limit
- * fields.
- *
- * @param null|array|string $only_these_fields
- * @return array
- */
- function toRawArray($only_these_fields = null)
- {
- $ret = [];
- if (is_string($only_these_fields)) {
- $only_these_fields = words($only_these_fields);
- }
- $fields = array_keys($this->db_fields());
- if (is_array($only_these_fields)) {
- $only_these_fields = array_filter(array_map(function ($s) {
- return is_string($s) ? strtolower($s) : null;
- }, $only_these_fields));
- $fields = array_intersect($only_these_fields, $fields);
- }
- foreach ($fields as $field) {
- if ($this->content[$field] instanceof I18NString) {
- $ret[$field] = $this->content[$field]->original();
- } elseif ($this->content[$field] === null) {
- $ret[$field] = null;
- } else {
- $ret[$field] = (string)$this->content[$field];
- }
- }
- return $ret;
- }
-
- /**
- * returns data of table row as assoc array
- * including related records with a 'has*' relationship
- * recurses one level without param
- *
- * $only_these_fields limits output for relationships in this way:
- * $only_these_fields = array('field_1',
- * 'field_2',
- * 'relation1',
- * 'relation2' => array('rel2_f1',
- * 'rel2_f2',
- * 'rel2_rel11' => array(
- * rel2_rel1_f1)
- * )
- * )
- * Here all fields of relation1 will be returned.
- *
- * @param null|array|string $only_these_fields limit returned fields
- * @return array
- */
- function toArrayRecursive($only_these_fields = null)
- {
- if (is_string($only_these_fields)) {
- $only_these_fields = words($only_these_fields);
- }
- if (is_null($only_these_fields)) {
- $only_these_fields = $this->known_slots();
- }
- $ret = $this->toArray($only_these_fields);
- $relations = [];
- if (is_array($only_these_fields)) {
- foreach ($only_these_fields as $key => $value) {
- if (!is_array($value) &&
- array_key_exists(strtolower($value), $this->relations)
- ) {
- $relations[strtolower($value)] = 0; //not null|array|string to stop recursion
- }
- if (array_key_exists(strtolower($key), $this->relations)) {
- $relations[strtolower($key)] = $value;
- }
- }
- }
- if (count($relations)) {
- foreach ($relations as $relation_name => $relation_only_these_fields) {
- $options = $this->getRelationOptions($relation_name);
- if ($options['type'] === 'has_one' ||
- $options['type'] === 'belongs_to') {
- $ret[$relation_name] =
- $this->{$relation_name}->
- toArrayRecursive($relation_only_these_fields);
- }
- if ($options['type'] === 'has_many' ||
- $options['type'] === 'has_and_belongs_to_many') {
- $ret[$relation_name] =
- $this->{$relation_name}->
- sendMessage('toArrayRecursive',
- [$relation_only_these_fields]);
- }
- }
- }
- return $ret;
- }
-
- /**
- * returns value of a column
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if getter for additional field could not be found
- * @param string $field
- * @return null|string|SimpleORMapCollection
- */
- public function getValue($field)
- {
- $field = strtolower($field);
-
- // No value defined, throw exception
- if (!in_array($field, $this->known_slots())) {
- throw new InvalidArgumentException(static::class . '::'.$field . ' not found.');
- }
-
- // Get value by getter
- if (isset($this->getter_setter_map()[$field]['get'])) {
- return call_user_func([$this, $this->getter_setter_map()[$field]['get']]);
- }
-
- // Get value from content
- if (array_key_exists($field, $this->content)) {
- return $this->content[$field];
- }
-
- // Get value from relation
- if (array_key_exists($field, $this->relations)) {
- $this->initRelation($field);
- return $this->relations[$field];
- }
-
- // Get value from additional_field
- if (isset($this->additional_fields()[$field]['get'])) {
- // Getter is defined as a closure
- if ($this->additional_fields()[$field]['get'] instanceof Closure) {
- return call_user_func_array($this->additional_fields()[$field]['get'], [$this, $field]);
- }
-
- // Getter is defined as a method of this object
- return call_user_func([$this, $this->additional_fields()[$field]['get']], $field);
- }
-
- // No value found, throw exception
- throw new RuntimeException('No value could be found for ' . static::class . '::' . $field);
- }
-
- /**
- * gets a value from a related object
- * only possible, if the relation has cardinality 1
- * e.g. 'has_one' or 'belongs_to'
- *
- * @param string $relation name of relation
- * @param string $field name of column
- * @throws InvalidArgumentException if no relation with given name is found
- * @return mixed the value from the related object
- */
- function getRelationValue($relation, $field)
- {
- $field = strtolower($field);
- $options = $this->getRelationOptions($relation);
- if ($options['type'] === 'has_one' || $options['type'] === 'belongs_to') {
- return $this->{$relation}->{$field} ?? null;
- } else {
- throw new InvalidArgumentException('Relation ' . $relation . ' not found or not applicable.');
- }
- }
-
- /**
- * returns default value for column
- *
- * @param string $field name of column
- * @return mixed the default value
- */
- function getDefaultValue($field)
- {
- $default_value = null;
- if (!isset($this->default_values()[$field])) {
- if (!in_array($field, $this->pk())) {
- $meta = $this->db_fields()[$field];
- if (isset($meta['default'])) {
- $default_value = $meta['default'];
- } elseif ($meta['null'] == 'NO') {
- if (strpos($meta['type'], 'text') !== false || strpos($meta['type'], 'char') !== false) {
- $default_value = '';
- }
- if (strpos($meta['type'], 'int') !== false) {
- $default_value = '0';
- }
- }
- }
- } else {
- $default_value = $this->default_values()[$field];
- }
- return $default_value;
- }
-
- /**
- * sets value of a column
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if setter for additional field could not be found
- * @param string $field
- * @param mixed $value
- * @return string
- */
- function setValue($field, $value)
- {
- $field = strtolower($field);
- $ret = false;
- if (in_array($field, $this->known_slots())) {
- if (isset($this->getter_setter_map()[$field]['set'])) {
- return call_user_func([$this, $this->getter_setter_map()[$field]['set']], $value);
- }
- if (array_key_exists($field, $this->content)) {
- if (array_key_exists($field, $this->serialized_fields())) {
- $ret = $this->setSerializedValue($field, $value);
- } elseif ($this->isI18nField($field)) {
- $ret = $this->setI18nValue($field, $value);
- } else {
- $ret = ($this->content[$field] = $value);
- }
- } elseif (isset($this->additional_fields()[$field]['set'])) {
- if ($this->additional_fields()[$field]['set'] instanceof Closure) {
- return call_user_func_array($this->additional_fields()[$field]['set'], [$this, $field, $value]);
- } else {
- return call_user_func([$this, $this->additional_fields()[$field]['set']], $field, $value);
- }
- } elseif (array_key_exists($field, $this->relations)) {
- $options = $this->getRelationOptions($field);
- if ($options['type'] === 'has_one' || $options['type'] === 'belongs_to') {
- if (is_a($value, $options['class_name'])) {
- $this->relations[$field] = $value;
- if ($options['type'] == 'has_one') {
- $foreign_key_value = call_user_func($options['assoc_func_params_func'], $this);
- call_user_func($options['assoc_foreign_key_setter'], $value, $foreign_key_value);
- } else {
- $assoc_foreign_key_value = call_user_func($options['assoc_foreign_key_getter'], $value, $this);
- if ($assoc_foreign_key_value === null) {
- throw new InvalidArgumentException(sprintf('trying to set belongs_to object of type: %s, but assoc_foreign_key: %s is null', get_class($value), $options['assoc_foreign_key']));
- }
- $this->setValue($options['foreign_key'], $assoc_foreign_key_value);
- }
- } else {
- throw new InvalidArgumentException(sprintf('relation %s expects object of type: %s', $field, $options['class_name']));
- }
- }
- if ($options['type'] == 'has_many' || $options['type'] == 'has_and_belongs_to_many') {
- if (is_array($value) || $value instanceof Traversable) {
- $new_ids = [];
- $old_ids = $this->{$field}->pluck('id');
- foreach ($value as $current) {
- if (!is_a($current, $options['class_name'])) {
- throw new InvalidArgumentException(sprintf('relation %s expects object of type: %s', $field, $options['class_name']));
- }
- if ($options['type'] == 'has_many') {
- $foreign_key_value = call_user_func($options['assoc_func_params_func'], $this);
- call_user_func($options['assoc_foreign_key_setter'], $current, $foreign_key_value);
- }
- if ($current->id !== null) {
- $new_ids[] = $current->id;
- $existing = $this->{$field}->find($current->id);
- if ($existing) {
- $existing->setData($current);
- } else {
- $this->{$field}->append($current);
- }
- } else {
- $this->{$field}->append($current);
- }
- }
- foreach (array_diff($old_ids, $new_ids) as $to_delete) {
- $this->{$field}->unsetByPK($to_delete);
- }
- } else {
- throw new InvalidArgumentException(sprintf('relation %s expects collection or array of objects of type: %s', $field, $options['class_name']));
- }
- }
- }
- } else {
- throw new InvalidArgumentException(get_class($this) . '::'. $field . ' not found.');
- }
- return $ret;
- }
-
- /**
- * magic method for dynamic properties
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if getter for additional field could not be found
- * @param string $field the column or additional field
- * @return null|string|SimpleORMapCollection
- */
- function __get($field)
- {
- return $this->getValue($field);
- }
- /**
- * magic method for dynamic properties
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if setter for additional field could not be found
- * @param string $field
- * @param string $value
- * @return string
- */
- function __set($field, $value)
- {
- return $this->setValue($field, $value);
- }
- /**
- * magic method for dynamic properties
- *
- * @param string $field
- * @return bool
- */
- function __isset($field)
- {
- $field = strtolower($field);
- if (in_array($field, $this->known_slots())) {
- $value = $this->getValue($field);
- return $value instanceOf SimpleORMapCollection ? (bool)count($value) : !is_null($value);
- } else {
- return false;
- }
- }
- /**
- * ArrayAccess: Check whether the given offset exists.
- *
- * @param string $offset
- * @return bool
- *
- * @todo Add bool return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetExists($offset)
- {
- return $this->__isset($offset);
- }
-
- /**
- * ArrayAccess: Get the value at the given offset.
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if getter for additional field could not be found
- * @param string $offset the column or additional field
- * @return null|string|SimpleORMapCollection
- *
- * @todo Add mixed return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetGet($offset)
- {
- return $this->getValue($offset);
- }
-
- /**
- * ArrayAccess: Set the value at the given offset.
- *
- * @throws InvalidArgumentException if column could not be found
- * @throws BadMethodCallException if setter for additional field could not be found
- * @param string $offset
- * @param mixed $value
- * @return void
- *
- * @todo Add void return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetSet($offset, $value)
- {
- $this->setValue($offset, $value);
- }
- /**
- * ArrayAccess: unset the value at the given offset (not applicable)
- *
- * @param string $offset
- * @return void
- *
- * @todo Add void return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetUnset($offset)
- {
-
- }
- /**
- * IteratorAggregate
- *
- * @return ArrayIterator
- *
- * @todo Add Traversable return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function getIterator()
- {
- return new ArrayIterator($this->toArray());
- }
- /**
- * Countable
- *
- * @return int
- *
- * @todo Add int return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function count()
- {
- return count($this->known_slots()) - count($this->relations);
- }
-
- /**
- * check if given column exists in table
- * @param string $field
- * @return boolean
- */
- function isField($field)
- {
- $field = strtolower($field);
- return isset($this->db_fields()[$field]);
- }
-
- /**
- * check if given relation exists in this class
- * @param string $field
- * @return boolean
- */
- function isRelation($field)
- {
- $field = strtolower($field);
- return array_key_exists($field, $this->relations);
- }
-
- /**
- * check if given column is additional
- * @param string $field
- * @return boolean
- */
- function isAdditionalField($field)
- {
- $field = strtolower($field);
- return isset($this->additional_fields()[$field]);
- }
-
- /**
- * check if given column is an alias
- * @param string $field
- * @return boolean
- */
- function isAliasField($field)
- {
- $field = strtolower($field);
- return isset($this->alias_fields()[$field]);
- }
-
- /**
- * check if given column is a multi-language field
- * @param string $field
- * @return boolean
- */
- function isI18nField($field)
- {
- $field = strtolower($field);
- return isset($this->i18n_fields()[$field]);
- }
-
- /**
- * set multiple column values
- * if second param is set, existing data in object will be
- * discarded and dirty state is cleared,
- * else new data overrides old data
- *
- * @param ?iterable $data assoc array
- * @param ?boolean $reset existing data in object will be discarded
- * @return int|bool number of columns changed
- */
- function setData($data, $reset = false)
- {
- $count = 0;
- if ($reset) {
- if ($this->applyCallbacks('before_initialize') === false) {
- return false;
- }
- $this->initializeContent();
- }
- if (is_iterable($data)) {
- foreach($data as $key => $value) {
- $key = strtolower($key);
- if (isset($this->db_fields()[$key])
- || isset($this->alias_fields()[$key])
- || isset($this->additional_fields()[$key]['set'])
- ) {
- $this->setValue($key, $value);
- ++$count;
- }
- }
- }
- if ($reset) {
- $this->applyCallbacks('after_initialize');
- }
- return $count;
- }
-
- /**
- * check if object exists in database
- * @return boolean
- */
- function isNew()
- {
- return $this->is_new;
- }
-
- /**
- * check if object was deleted
- *
- * @return boolean
- */
- function isDeleted()
- {
- return $this->is_deleted;
- }
-
- /**
- * set object to new state
- * @param boolean $is_new
- * @return boolean
- */
- function setNew($is_new)
- {
- return $this->is_new = $is_new;
- }
-
- /**
- * returns sql clause with current table and pk
- * @throws UnexpectedValueException if the primary key is incomplete
- * @return boolean|array<string>
- */
- function getWhereQuery()
- {
- $where_query = null;
- $pk_not_set = [];
- foreach ($this->pk() as $key) {
- $pk = $this->content_db[$key] ?? $this->content[$key] ?? null;
- if (isset($pk)) {
- $where_query[] = "`{$this->db_table()}`.`{$key}` = " . DBManager::get()->quote($pk);
- } else {
- $pk_not_set[] = $key;
- }
- }
- if (!$where_query || count($pk_not_set)){
- if ($this->isNew()) {
- return false;
- } else {
- throw new UnexpectedValueException(sprintf("primary key incomplete: %s must not be null", join(',',$pk_not_set)));
- }
- }
- return $where_query;
- }
-
- /**
- * restore entry from database
- * @return boolean
- */
- function restore()
- {
- $where_query = $this->getWhereQuery();
- $id = $this->getId();
- if ($where_query) {
- if ($this->applyCallbacks('before_initialize') === false) {
- return false;
- }
- $this->initializeContent();
- $query = "SELECT * FROM `{$this->db_table()}` WHERE "
- . join(" AND ", $where_query);
- $st = DBManager::get()->prepare($query);
- $st->execute();
- $st->setFetchMode(PDO::FETCH_INTO , $this);
- if ($st->fetch()) {
- $this->setNew(false);
- $this->applyCallbacks('after_initialize');
- return true;
- }
- }
- $this->setData([], true);
- $this->setNew(true);
- if (isset($id)) {
- $this->setId($id);
- }
- return false;
- }
-
- /**
- * store entry in database
- *
- * @throws UnexpectedValueException if there are forbidden NULL values
- * @return number|boolean
- */
- function store()
- {
- // Set id or prepare setting of id
- if ($this->isNew() && $this->getId() === null) {
- // Explicitly set id to 0 if auto increment pk is null
- if ($this->hasAutoIncrementColumn()) {
- $this->setId(0);
- } else {
- $this->setId($this->getNewId());
- }
- }
-
- if ($this->applyCallbacks('before_store') === false) {
- return false;
- }
-
- $ret = 0;
-
- if (!$this->isDeleted() && ($this->isDirty() || $this->isNew())) {
- $callback = $this->isNew() ? 'before_create' : 'before_update';
- if ($this->applyCallbacks($callback) === false) {
- return false;
- }
-
- // Collect i18n contents
- $i18ncontent = [];
- foreach (array_keys($this->i18n_fields()) as $field) {
- if ($this->content[$field] instanceof I18NString) {
- $i18ncontent[$field] = $this->content[$field];
- $this->content[$field] = $this->content[$field]->original();
- $this->content_db[$field] = $this->content_db[$field]->original();
- }
- }
-
- // Create sql data assignment chunks
- foreach ($this->db_fields() as $field => $meta) {
- $value = $this->content[$field];
- if ($field == 'chdate' && !$this->isFieldDirty($field) && $this->isDirty()) {
- $value = time();
- }
- if ($field == 'mkdate') {
- if ($this->isNew()) {
- if (!$this->isFieldDirty($field)) {
- $value = time();
- }
- } else {
- continue;
- }
- }
- if ($value === null && $meta['null'] == 'NO') {
- throw new UnexpectedValueException($this->db_table() . '.' . $field . ' must not be null.');
- }
- if (is_float($value)) {
- $value = str_replace(',', '.', $value);
- }
- $this->content[$field] = $value;
- $query_part[] = "`$field` = " . DBManager::get()->quote($value) . " ";
- }
-
- // Create store query
- if (!$this->isNew()) {
- $where_query = $this->getWhereQuery();
- $query = "UPDATE `{$this->db_table()}` SET "
- . implode(',', $query_part);
- $query .= " WHERE " . join(" AND ", $where_query);
- } else {
- $query = "INSERT INTO `{$this->db_table()}` SET "
- . implode(',', $query_part);
- }
- $ret = DBManager::get()->exec($query);
-
- // Retrieve generated id from database if pk is an auto increment
- // column
- if ($this->isNew()) {
- if ($this->hasAutoIncrementColumn() && !$this->getId()) {
- $this->setId(DBManager::get()->lastInsertId());
- }
- }
-
- // Store i18n contents
- foreach ($i18ncontent as $field => $one) {
- $meta = [
- 'object_id' => $this->getId(),
- 'table' => $this->db_table(),
- 'field' => $field
- ];
- $one->setMetadata($meta);
- $one->storeTranslations();
- if (!$this->content[$field] instanceof I18NString) {
- $this->content[$field] = $one;
- $this->content_db[$field] = clone $one;
- }
- }
-
- // Apply callbacks
- $this->applyCallbacks($this->isNew() ? 'after_create' : 'after_update');
- }
- $rel_ret = $this->storeRelations();
-
- $this->applyCallbacks('after_store');
-
- if ($ret || $rel_ret) {
- $this->restore();
- }
- return $ret + $rel_ret;
- }
-
- /**
- * sends a store message to all initialized related objects
- * if a relation has a callback for 'on_store' configured, the callback
- * is instead invoked
- *
- * @param null|array|string $only_these
- * @return int|false number addition of all return values, false if none was called
- */
- protected function storeRelations($only_these = null)
- {
- $ret = false;
- if (is_string($only_these)) {
- $only_these = words($only_these);
- }
- $relations = array_keys($this->relations);
- if (is_array($only_these)) {
- $only_these = array_filter(array_map(function ($s) {
- return is_string($s) ? strtolower($s) : null;
- }, $only_these));
- $relations = array_intersect($only_these, $relations);
- }
- foreach ($relations as $relation) {
- $options = $this->getRelationOptions($relation);
- if (isset($options['on_store']) &&
- ($options['type'] === 'has_one' ||
- $options['type'] === 'has_many' ||
- $options['type'] === 'has_and_belongs_to_many')) {
- if ($options['on_store'] instanceof Closure) {
- $ret += call_user_func($options['on_store'], $this, $relation);
- } elseif (isset($this->relations[$relation])) {
- $foreign_key_value = call_user_func($options['assoc_func_params_func'], $this);
- if ($options['type'] === 'has_one') {
- call_user_func($options['assoc_foreign_key_setter'], $this->{$relation}, $foreign_key_value);
- $ret = call_user_func([$this->{$relation}, 'store']);
- } elseif ($options['type'] === 'has_many') {
- foreach ($this->{$relation} as $r) {
- call_user_func($options['assoc_foreign_key_setter'], $r, $foreign_key_value);
- }
- $ret += array_sum(call_user_func([$this->{$relation}, 'sendMessage'], 'store'));
- $ret += array_sum(call_user_func([$this->{$relation}->getDeleted(), 'sendMessage'], 'delete'));
- } else {
- call_user_func([$this->{$relation}, 'sendMessage'], 'store');
- $to_delete = array_filter($this->{$relation}->getDeleted()->pluck($options['assoc_foreign_key']));
- $to_insert = array_filter($this->{$relation}->pluck($options['assoc_foreign_key']));
- $sql = "DELETE FROM `" . $options['thru_table'] ."` WHERE `" . $options['thru_key'] ."` = ? AND `" . $options['thru_assoc_key'] . "` = ?";
- $st = DBManager::get()->prepare($sql);
- foreach ($to_delete as $one_value) {
- $st->execute([$foreign_key_value, $one_value]);
- $ret += $st->rowCount();
- }
- $sql = "INSERT IGNORE INTO `" . $options['thru_table'] ."` SET `" . $options['thru_key'] ."` = ?, `" . $options['thru_assoc_key'] . "` = ?";
- $st = DBManager::get()->prepare($sql);
- foreach ($to_insert as $one_value) {
- $st->execute([$foreign_key_value, $one_value]);
- $ret += $st->rowCount();
- }
- }
- }
- }
- }
- return $ret;
- }
-
- /**
- * set chdate column to current timestamp
- * @return boolean
- */
- function triggerChdate()
- {
- if ($this->db_fields()['chdate']) {
- $this->content['chdate'] = time();
- if ($where_query = $this->getWhereQuery()) {
- DBManager::get()->exec("UPDATE `{$this->db_table()}` SET chdate={$this->content['chdate']}
- WHERE ". join(" AND ", $where_query));
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * delete entry from database
- * the object is cleared, but is not(!) turned to new state
- * @return bool|int number of deleted rows
- */
- function delete()
- {
- $ret = false;
- if (!$this->isDeleted() && !$this->isNew()) {
- if ($this->applyCallbacks('before_delete') === false) {
- return false;
- }
- $ret = $this->deleteRelations();
- $where_query = $this->getWhereQuery();
- if ($where_query) {
- $query = "DELETE FROM `{$this->db_table()}` WHERE "
- . join(" AND ", $where_query);
- $ret += DBManager::get()->exec($query);
- }
- $this->is_deleted = true;
- $this->applyCallbacks('after_delete');
-
- // Remove i18n translations
- if (I18N::isEnabled()) {
- foreach (array_keys($this->i18n_fields()) as $field) {
- if ($this->content[$field] instanceof I18NString) {
- $this->content[$field]->removeTranslations();
- }
- }
- }
- }
- $this->setData([], true);
- return $ret;
- }
-
- /**
- * sends a delete message to all related objects
- * if a relation has a callback for 'on_delete' configured, the callback
- * is invoked instead
- *
- * @return bool|int addition of all return values, false if none was called
- */
- protected function deleteRelations()
- {
- $ret = false;
- foreach (array_keys($this->relations) as $relation) {
- $options = $this->getRelationOptions($relation);
- if (isset($options['on_delete']) &&
- ($options['type'] === 'has_one' ||
- $options['type'] === 'has_many' ||
- $options['type'] === 'has_and_belongs_to_many')) {
- if ($options['on_delete'] instanceof Closure) {
- $ret += call_user_func($options['on_delete'], $this, $relation);
- } else {
- if ($options['type'] === 'has_one' || $options['type'] === 'has_many') {
- $this->initRelation($relation);
- if (isset($this->relations[$relation])) {
- if ($options['type'] === 'has_one') {
- $ret += call_user_func([$this->{$relation}, 'delete']);
- } elseif ($options['type'] === 'has_many') {
- $ret += array_sum(call_user_func([$this->{$relation}, 'sendMessage'], 'delete'));
- }
- }
- } else {
- $foreign_key_value = call_user_func($options['assoc_func_params_func'], $this);
- $sql = "DELETE FROM `" . $options['thru_table'] ."` WHERE `" . $options['thru_key'] ."` = ?";
- $st = DBManager::get()->prepare($sql);
- $st->execute([$foreign_key_value]);
- $ret += $st->rowCount();
- }
- }
- $this->relations[$relation] = null;
- }
- }
- return $ret;
- }
-
- /**
- * init internal content arrays with nulls or defaults
- *
- * @throws UnexpectedValueException if there is an unmatched alias
- * @return void
- */
- protected function initializeContent()
- {
- $this->content = [];
- foreach (array_keys($this->db_fields()) as $field) {
- $this->content[$field] = null;
- $this->content_db[$field] = null;
- $this->setValue($field, $this->getDefaultValue($field));
- }
- foreach ($this->alias_fields() as $alias => $field) {
- if (isset($this->db_fields()[$field])) {
- $this->content[$alias] =& $this->content[$field];
- $this->content_db[$alias] =& $this->content_db[$field];
- } else {
- throw new UnexpectedValueException(sprintf('Column %s not found for alias %s', $field, $alias));
- }
- }
- foreach (array_keys($this->relations) as $one) {
- $this->relations[$one] = null;
- }
- $this->additional_data = [];
- }
-
- /**
- * checks if at least one field was modified since last restore
- *
- * @return boolean
- */
- public function isDirty()
- {
- foreach (array_keys($this->db_fields()) as $field) {
- if ($this->isFieldDirty($field)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * checks if given field was modified since last restore
- *
- * @param string $field
- * @return boolean
- */
- public function isFieldDirty($field)
- {
- $field = strtolower($field);
- if ($this->content[$field] === null || $this->content_db[$field] === null) {
- return $this->content[$field] !== $this->content_db[$field];
- } else if ($this->content[$field] instanceof I18NString || $this->content_db[$field] instanceof I18NString) {
- return $this->content[$field] != $this->content_db[$field];
- } else {
- return (string)$this->content[$field] !== (string)$this->content_db[$field];
- }
- }
-
- /**
- * reverts value of given field to last restored value
- *
- * @param string $field
- * @return mixed the restored value
- */
- public function revertValue($field)
- {
- $field = strtolower($field);
- return ($this->content[$field] = $this->content_db[$field]);
- }
-
- /**
- * returns unmodified value of given field
- *
- * @param string $field
- * @throws InvalidArgumentException
- * @return mixed
- */
- public function getPristineValue($field)
- {
- $field = strtolower($field);
- if (array_key_exists($field, $this->content_db)) {
- return $this->content_db[$field];
- } else {
- throw new InvalidArgumentException(get_class($this) . '::'. $field . ' not found.');
- }
- }
-
- /**
- * intitalize a relationship and get related record(s)
- *
- * @param string $relation name of relation
- * @throws InvalidArgumentException if the relation does not exists
- * @return void
- */
- public function initRelation($relation)
- {
- if (!array_key_exists($relation, $this->relations)) {
- throw new InvalidArgumentException('Unknown relation: ' . $relation);
- }
- if ($this->relations[$relation] === null) {
- $options = $this->getRelationOptions($relation);
- $to_call = [$options['class_name'], $options['assoc_func']];
- if (!is_callable($to_call)) {
- throw new RuntimeException('assoc_func: ' . join('::', $to_call) . ' is not callable.' );
- }
- $params = $options['assoc_func_params_func'];
- if ($options['type'] === 'has_many') {
- $records = function($record) use ($to_call, $params, $options) {
- $p = (array)$params($record);
- return call_user_func_array($to_call, array_merge(count($p) ? $p : [null], [$options['order_by'] ?? null]));
- };
- $this->relations[$relation] = new SimpleORMapCollection($records, $options, $this);
- } elseif ($options['type'] === 'has_and_belongs_to_many') {
- $records = function($record) use ($to_call, $params, $options) {$p = (array)$params($record); return call_user_func_array($to_call, array_merge(count($p) ? $p : [null], [$options]));};
- $this->relations[$relation] = new SimpleORMapCollection($records, $options, $this);
- } else {
- $p = (array)$params($this);
- $records = call_user_func_array($to_call, count($p) ? $p : [null]);
- $result = is_array($records) ? ($records[0] ?? null) : $records;
- $this->relations[$relation] = $result;
- }
- }
- }
-
- /**
- * clear data for a relationship
- *
- * @param string $relation name of relation
- * @throws InvalidArgumentException if teh relation does not exists
- * @return void
- */
- public function resetRelation($relation)
- {
- if (!array_key_exists($relation, $this->relations)) {
- throw new InvalidArgumentException('Unknown relation: ' . $relation);
- }
- $this->relations[$relation] = null;
- }
-
- /**
- * invoke registered callbacks for given type
- * if one callback returns false the following will not
- * be invoked
- *
- * @param string $type type of callback
- * @return bool return value from last callback
- */
- protected function applyCallbacks($type)
- {
- $ok = true;
- foreach ($this->registered_callbacks()[$type] as $cb) {
- if ($cb instanceof Closure) {
- $function = $cb;
- $params = [$this, $type, $cb];
- } else {
- $function = [$this, $cb];
- $params = [$type];
- };
- $ok = call_user_func_array($function, $params);
- if ($ok === false) {
- break;
- }
- }
- return $ok;
- }
-
- /**
- * register given callback for one or many possible callback types
- * callback param could be a closure or method name of current class
- *
- * @param string|array $types types to register callback for
- * @param callable $cb callback
- * @throws InvalidArgumentException if the callback type is not known
- * @return number of registered callbacks
- */
- protected static function registerCallback($types, $cb)
- {
- trigger_error(__METHOD__ . ' is deprecated. Please use the configuration in configure().', E_USER_DEPRECATED);
-
- $types = is_array($types) ? $types : words($types);
- $reg = 0;
- foreach ($types as $type) {
- if (isset(static::registered_callbacks()[$type])) {
- $found = array_search($cb, self::$config[static::class]['registered_callbacks'][$type], true);
- if ($found === false) {
- self::$config[static::class]['registered_callbacks'][$type][] = $cb;
- $reg++;
- }
- } else {
- throw new InvalidArgumentException('Unknown callback type: ' . $type);
- }
- }
- return $reg;
- }
-
- /**
- * unregister given callback for one or many possible callback types
- *
- * @param string|array $types types to unregister callback for
- * @param mixed $cb
- * @throws InvalidArgumentException if the callback type is not known
- * @return number of unregistered callbacks
- */
- protected static function unregisterCallback($types, $cb)
- {
- trigger_error(__METHOD__ . ' is deprecated. Please use the configuration in configure().', E_USER_DEPRECATED);
-
- $types = is_array($types) ? $types : words($types);
- foreach ($types as $type) {
- if (isset(static::registered_callbacks()[$type])) {
- $found = array_search($cb, self::$config[static::class]['registered_callbacks'][$type], true);
- if ($found !== false) {
- $unreg++;
- unset(self::$config[static::class]['registered_callbacks'][$type][$found]);
- }
- } else {
- throw new InvalidArgumentException('Unknown callback type: ' . $type);
- }
- }
- return $unreg;
- }
-
- /**
- * default callback used to map specific callbacks to NotificationCenter
- *
- * @param string $cb_type callback type
- * @return void|boolean
- */
- protected function cbNotificationMapper($cb_type)
- {
- if (isset($this->notification_map()[$cb_type])) {
- try {
- foreach(words($this->notification_map()[$cb_type]) as $notification) {
- NotificationCenter::postNotification($notification, $this);
- }
- } catch (NotificationVetoException $e) {
- return false;
- }
- }
- }
-
- /**
- * default callback used to map specific callbacks to NotificationCenter
- *
- * @param string $cb_type callback type
- * @return void|boolean
- */
- protected function cbAfterInitialize($cb_type)
- {
- foreach (array_keys($this->db_fields()) as $field) {
- if (is_object($this->content[$field])) {
- $this->content_db[$field] = clone $this->content[$field];
- } else {
- $this->content_db[$field] = $this->content[$field];
- }
- }
- }
-
- /**
- * default setter used to proxy serialized fields with
- * ArrayObjects
- *
- * @param string $field column name
- * @param mixed $value value
- * @return mixed
- */
- protected function setSerializedValue($field, $value)
- {
- $object_type = $this->serialized_fields()[$field];
- if (is_null($value) || $value instanceof $object_type) {
- $this->content[$field] = $value;
- } else {
- $this->content[$field] = new $object_type($value);
- }
- return $this->content[$field];
- }
-
- /**
- * default setter used to proxy I18N fields with
- * I18NString
- *
- * @param string $field column name
- * @param mixed $value value
- * @return mixed
- */
- protected function setI18nValue($field, $value)
- {
- $meta = ['object_id' => $this->getId(),
- 'table' => $this->db_table(),
- 'field' => $field];
- if ($value instanceof I18NString) {
- $value->setMetadata($meta);
- $this->content[$field] = $value;
- } else {
- $this->content[$field] = new I18NString($value, null, $meta);
- }
- return $this->content[$field];
- }
-
- /**
- * Cleans up this object. This essentially reset all relations of
- * this object and marks them as unused so that the garbage collector may
- * remove the objects.
- *
- * Use this function when you ran into memory problems and need to free
- * some memory;
- *
- * @return void
- */
- public function cleanup()
- {
- foreach ($this->relations as $relation => $object) {
- if ($object instanceof SimpleORMap || $object instanceof SimpleORMapCollection) {
- $this->relations[$relation]->cleanup();
- }
- $this->resetRelation($relation);
- }
- }
-}
diff --git a/lib/models/SimpleORMapCollection.class.php b/lib/models/SimpleORMapCollection.class.php
deleted file mode 100644
index f06ee17..0000000
--- a/lib/models/SimpleORMapCollection.class.php
+++ /dev/null
@@ -1,261 +0,0 @@
-<?php
-/**
- * SimpleORMapCollection.class.php
- * simple object-relational mapping
- *
- * 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 André Noack <noack@data-quest.de>
- * @copyright 2012 Stud.IP Core-Group
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- *
- * @extends SimpleCollection<SimpleORMap>
- *
- * @template T of SimpleORMap
- */
-class SimpleORMapCollection extends SimpleCollection
-{
- /**
- * @var int Exception error code denoting a wrong type of objects.
- */
- const WRONG_OBJECT_TYPE = 1;
-
- /**
- * @var int Exception error code denoting that an object of this `id` already exists.
- */
- const OBJECT_EXISTS = 2;
-
- /**
- * the record object this collection belongs to
- *
- * @var ?SimpleORMap
- */
- protected $related_record;
-
- /**
- * relation options
- * @var array
- */
- protected $relation_options = [];
-
- /**
- * creates a collection from an array of objects
- * all objects should be of the same type
- *
- * @throws InvalidArgumentException if first entry is not SimpleOrMap
- * @param T[] $data array with SimpleORMap objects
- * @param bool $strict check every element for correct type and unique pk
- * @return SimpleORMapCollection<T>
- */
- public static function createFromArray(array $data, $strict = true)
- {
- $ret = new SimpleORMapCollection();
- if (count($data)) {
- $first = current($data);
- if ($first instanceof SimpleORMap) {
- $ret->setClassName(get_class($first));
- if ($strict) {
- foreach ($data as $one) {
- $ret[] = $one;
- }
- } else {
- $ret->exchangeArray($data);
- }
- } else {
- throw new InvalidArgumentException('This collection only accepts objects derived from SimpleORMap', self::WRONG_OBJECT_TYPE);
- }
- }
- return $ret;
- }
-
- /**
- * Constructor
- *
- * @param ?Closure $finder callable to fill collection
- * @param ?array $options relationship options
- * @param SimpleORMap|null $record related record
- */
- public function __construct(Closure $finder = null, array $options = null, SimpleORMap $record = null)
- {
- $this->relation_options = $options;
- $this->related_record = $record;
- parent::__construct($finder === null ? [] : $finder);
- }
-
- /**
- * Sets the value at the specified index
- * checks if the value is an object of specified class
- *
- * @see ArrayObject::offsetSet()
- * @throws InvalidArgumentException if the given model does not fit (wrong type or id)
- *
- * @todo Add void return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function offsetSet($index, $newval)
- {
- if (!is_null($index)) {
- $index = (int)$index;
- }
- if (!is_a($newval, $this->getClassName())) {
- throw new InvalidArgumentException('This collection only accepts objects of type: ' . $this->getClassName(), self::WRONG_OBJECT_TYPE);
- }
- if ($this->related_record && $this->relation_options['type'] === 'has_many') {
- $foreign_key_value = call_user_func($this->relation_options['assoc_func_params_func'], $this->related_record);
- call_user_func($this->relation_options['assoc_foreign_key_setter'], $newval, $foreign_key_value);
- }
- if ($newval->id !== null) {
- $exists = $this->find($newval->id);
- if ($exists) {
- throw new InvalidArgumentException('Element could not be appended, element with id: ' . $exists->id . ' is in the way', self::OBJECT_EXISTS);
- }
- }
- parent::offsetSet($index, $newval);
- }
-
- /**
- * sets the allowed class name
- * @param class-string $class_name
- * @return void
- */
- public function setClassName($class_name)
- {
- $this->relation_options['class_name'] = strtolower($class_name);
- $this->deleted->relation_options['class_name'] = strtolower($class_name);
- }
-
- /**
- * sets the related record
- *
- * @param SimpleORMap $record
- * @return void
- */
- public function setRelatedRecord(SimpleORMap $record)
- {
- $this->related_record = $record;
- }
-
- /**
- * gets the allowed classname
- *
- * @return string
- */
- public function getClassName()
- {
- return strtolower($this->relation_options['class_name']);
- }
-
- /**
- * reloads the elements of the collection
- * by calling the finder function
- *
- * @throws InvalidArgumentException
- * @return ?int number of records after refresh
- */
- public function refresh()
- {
- if (is_callable($this->finder)) {
- $data = call_user_func($this->finder, $this->related_record);
- foreach ($data as $one) {
- if (!is_a($one, $this->getClassName())) {
- throw new InvalidArgumentException('This collection only accepts objects of type: ' . $this->getClassName(), self::WRONG_OBJECT_TYPE);
- }
- }
- $this->exchangeArray($data);
- $this->deleted->exchangeArray([]);
- return $this->last_count = $this->count();
- }
-
- return null;
- }
-
- /**
- * returns element with given primary key value
- *
- * @param string $value primary key value to search for
- * @return ?T
- */
- public function find($value)
- {
- return $this->findOneBy('id', $value);
- }
-
- /**
- * returns the collection as grouped array
- * first param is the column to group by, it becomes the key in
- * the resulting array, default is pk. Limit returned fields with second param
- * The grouped entries can optoionally go through the given
- * callback. If no callback is provided, only the first grouped
- * entry is returned, suitable for grouping by unique column
- *
- * @param string $group_by the column to group by, pk if ommitted
- * @param mixed $only_these_fields limit returned fields
- * @param ?callable $group_func closure to aggregate grouped entries
- * @return array assoc array
- */
- public function toGroupedArray($group_by = 'id', $only_these_fields = null, callable $group_func = null)
- {
- $result = [];
- foreach ($this as $record) {
- $key = $record->getValue($group_by);
- if (is_array($key)) {
- $key = join('_', $key);
- }
- $result[$key][] = $record->toArray($only_these_fields);
- }
- if ($group_func === null) {
- $group_func = 'current';
- }
- return array_map($group_func, $result);
- }
-
- /**
- * mark element(s) for deletion
- * element(s) with given primary key are moved to
- * internal deleted collection
- *
- * @param string $id primary key of element
- * @return int number of unsetted elements
- */
- public function unsetByPk($id)
- {
- return $this->unsetBy('id', $id);
- }
-
- /**
- * merge in another collection, elements must be of
- * the same type, if an element already exists it is
- * replaced or ignored depending on second param
- *
- * @param SimpleORMapCollection $a_collection
- * @param string $mode 'replace' or 'ignore'
- * @return void
- */
- public function merge(SimpleCollection $a_collection, string $mode = 'ignore')
- {
- $mode = func_get_arg(1);
- foreach ($a_collection as $element) {
- try {
- /**
- * @throws InvalidArgumentException
- * @see SimpleORMapCollection::offsetSet()
- */
- $this[] = $element;
- } catch (InvalidArgumentException $e) {
- if ($e->getCode() === self::OBJECT_EXISTS) {
- if ($mode === 'replace') {
- $this->unsetByPk($element->id);
- $this[] = $element;
- } // else $mode means 'ignore'
- } else {
- throw $e;
- }
- }
- }
- $this->storage = array_values($this->storage);
- }
-}
diff --git a/lib/models/StudipCacheOperation.php b/lib/models/StudipCacheOperation.php
index e9c8738..d2287c3 100644
--- a/lib/models/StudipCacheOperation.php
+++ b/lib/models/StudipCacheOperation.php
@@ -42,7 +42,7 @@ class StudipCacheOperation extends SimpleORMap
*/
public static function apply(StudipCache $cache)
{
- self::findEachBySQL(function ($item) use ($cache) {
+ self::findEachBySQL(function (StudipCacheOperation $item) use ($cache): void {
$parameters = unserialize($item->parameters);
array_unshift($parameters, $item->cache_key);
call_user_func_array([$cache, $item->operation], $parameters);
diff --git a/lib/models/StudipComment.class.php b/lib/models/StudipComment.php
index 2e0389d..79610f8 100644
--- a/lib/models/StudipComment.class.php
+++ b/lib/models/StudipComment.php
@@ -23,7 +23,7 @@
// +---------------------------------------------------------------------------+
/**
- * StudipComment.class.php
+ * StudipComment.php
*
*
*
diff --git a/lib/models/StudipEvaluation.php b/lib/models/StudipEvaluation.php
deleted file mode 100644
index 5441db8..0000000
--- a/lib/models/StudipEvaluation.php
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-/**
- * Evaluation.php
- * model class for table Evaluation
- *
- * 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 Florian Bieringer <florian.bieringer@uni-passau.de>
- * @copyright 2014 Stud.IP Core-Group
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- * @since 3.0
- *
- * @property string $id alias column for eval_id
- * @property string $eval_id database column
- * @property string $author_id database column
- * @property string $title database column
- * @property string $text database column
- * @property int|null $startdate database column
- * @property int|null $stopdate database column
- * @property int|null $timespan database column
- * @property int $mkdate database column
- * @property int $chdate database column
- * @property int $anonymous database column
- * @property int $visible database column
- * @property int $shared database column
- * @property User $author belongs_to User
- * @property SimpleORMapCollection|User[] $participants has_and_belongs_to_many User
- * @property mixed $enddate additional field
- */
-class StudipEvaluation extends SimpleORMap
-{
- protected static function configure($config = [])
- {
- $config['db_table'] = 'eval';
-
- $config['belongs_to']['author'] = [
- 'class_name' => User::class,
- 'foreign_key' => 'author_id'
- ];
- $config['has_and_belongs_to_many']['participants'] = [
- 'class_name' => User::class,
- 'thru_table' => 'eval_user'
- ];
-
- $config['additional_fields']['enddate'] = true;
-
- parent::configure($config);
- }
-
- /**
- * Fetches all evaluations for a specific range_id
- *
- * @param String $range_id the range id
- * @return Array All evaluations for that range
- */
- public static function findByRange_id($range_id)
- {
- return self::findThru($range_id, [
- 'thru_table' => 'eval_range',
- 'thru_key' => 'range_id',
- 'thru_assoc_key' => 'eval_id',
- 'assoc_foreign_key' => 'eval_id'
- ]);
- }
-
- /**
- * Returns the enddate of a evaluation. Returns null if stop is manual
- *
- * @return stopdate or null
- */
- public function getEnddate()
- {
- if ($this->stopdate) {
- return $this->stopdate;
- }
- if ($this->timespan) {
- return $this->startdate + $this->timespan;
- }
- return null;
- }
-
- function getNumberOfVotes ()
- {
- return DBManager::get()->fetchColumn("SELECT count(DISTINCT user_id) FROM eval_user WHERE eval_id = ?", [$this->id]);
- }
-}
diff --git a/lib/models/StudipNews.class.php b/lib/models/StudipNews.php
index 607f9d3..ccb1828 100644
--- a/lib/models/StudipNews.class.php
+++ b/lib/models/StudipNews.php
@@ -21,7 +21,7 @@
require_once 'lib/object.inc.php';
/**
- * StudipNews.class.php
+ * StudipNews.php
*
* @author André Noack <noack@data-quest>, Suchi & Berg GmbH <info@data-quest.de>
* @author Arne Schröder <schroeder@data-quest>
@@ -44,6 +44,7 @@ require_once 'lib/object.inc.php';
* @property SimpleORMapCollection|StudipComment[] $comments has_many StudipComment
* @property SimpleORMapCollection|NewsRoles[] $news_roles has_many NewsRoles
* @property User $owner belongs_to User
+ * @property int $views additional field
*/
class StudipNews extends SimpleORMap implements PrivacyObject
{
@@ -72,8 +73,15 @@ class StudipNews extends SimpleORMap implements PrivacyObject
'on_delete' => 'delete'
];
- $config['i18n_fields']['topic'] = true;
- $config['i18n_fields']['body'] = true;
+ $config['additional_fields'] = [
+ 'views' => [
+ 'get' => function (StudipNews $news): int {
+ return object_return_views($news->id);
+ },
+ ],
+ ];
+
+ $config['i18n_fields'] = ['topic', 'body'];
// Strip <admin_msg> from news body
$config['registered_callbacks']['after_initialize'][] = function ($news) {
@@ -292,7 +300,7 @@ class StudipNews extends SimpleORMap implements PrivacyObject
$news_result = $statement->fetchGrouped();
$objects = [$area => []];
- foreach($news_result as $id => $result) {
+ foreach ($news_result as $id => $result) {
$objects[$area][$id] = [
'range_id' => $result['range_id'],
'title' => $result['title'] ?? '',
@@ -307,8 +315,7 @@ class StudipNews extends SimpleORMap implements PrivacyObject
} elseif ($area === 'user') {
if ($GLOBALS['user']->id === $result['userid']) {
$objects[$area][$id]['title'] = _('Ankündigungen auf Ihrer Profilseite');
- }
- else {
+ } else {
$objects[$area][$id]['title'] = sprintf(_('Ankündigungen auf der Profilseite von %s'), get_fullname($result['userid']));
}
} elseif ($area === 'global') {
diff --git a/lib/models/StudipScmEntry.class.php b/lib/models/StudipScmEntry.php
index 7001a4a..30c13d3 100644
--- a/lib/models/StudipScmEntry.class.php
+++ b/lib/models/StudipScmEntry.php
@@ -1,6 +1,6 @@
<?php
/**
- * StudipScmEntry.class.php
+ * StudipScmEntry.php
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/StudipStudyArea.class.php b/lib/models/StudipStudyArea.php
index 8da8e16..8da8e16 100644
--- a/lib/models/StudipStudyArea.class.php
+++ b/lib/models/StudipStudyArea.php
diff --git a/lib/models/StudyCourse.class.php b/lib/models/StudyCourse.php
index faf6df4..91937ea 100644
--- a/lib/models/StudyCourse.class.php
+++ b/lib/models/StudyCourse.php
@@ -1,6 +1,6 @@
<?php
/**
- * StudyCourse.class.php
+ * StudyCourse.php
* model class for table studiengang
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/ToolActivation.php b/lib/models/ToolActivation.php
index a4a4de2..4209a20 100644
--- a/lib/models/ToolActivation.php
+++ b/lib/models/ToolActivation.php
@@ -1,6 +1,6 @@
<?php
/**
- * ToolActivation.class.php
+ * ToolActivation.php
* model class for table tools_activated
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/User.class.php b/lib/models/User.php
index 056b48a..3fcc3f5 100644
--- a/lib/models/User.class.php
+++ b/lib/models/User.php
@@ -1,6 +1,6 @@
<?php
/**
- * User.class.php
+ * User.php
* model class for combined auth_user_md5/user_info record
* this class represents one user, the attributes from tables
* auth_user_md5 and user_info were merged.
@@ -52,6 +52,9 @@
* @property SimpleORMapCollection|Kategorie[] $profile_categories has_many Kategorie
* @property SimpleORMapCollection|MvvContact[] $mvv_assignments has_many MvvContact
* @property SimpleORMapCollection|CourseMemberNotification[] $course_notifications has_many CourseMemberNotification
+ * @property SimpleORMapCollection|BlubberThread[] $blubber_threads has_many BlubberThread
+ * @property SimpleORMapCollection|BlubberComment[] $blubber_comments has_many BlubberComment
+ * @property SimpleORMapCollection|BlubberMention[] $blubber_mentions has_many BlubberMention
* @property UserInfo $info has_one UserInfo
* @property UserOnline $online has_one UserOnline
* @property Courseware\Unit $courseware_units has_one Courseware\Unit
@@ -206,6 +209,20 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
'assoc_foreign_key' => 'author_id'
];
+ // Blubber relations
+ $config['has_many']['blubber_threads'] = [
+ 'class_name' => BlubberThread::class,
+ 'on_delete' => 'delete',
+ ];
+ $config['has_many']['blubber_comments'] = [
+ 'class_name' => BlubberComment::class,
+ 'on_delete' => 'delete',
+ ];
+ $config['has_many']['blubber_mentions'] = [
+ 'class_name' => BlubberMention::class,
+ 'on_delete' => 'delete',
+ ];
+
$config['additional_fields']['config']['get'] = function ($user) {
return UserConfig::get($user->id);
};
@@ -378,7 +395,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
}
/**
- * Temporary migrate to User.class.php
+ * Temporary migrate to User.php
*
* @param $attributes
* @return array
@@ -795,9 +812,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
$activeVotes = [];
$stoppedVotes = [];
}
- // Evaluations
- $evalDB = new EvaluationDB();
- $activeEvals = $evalDB->getEvaluationIDs($this->id, EVAL_STATE_ACTIVE);
+
// Free datafields
$data_fields = DataFieldEntry::getDataFieldEntries($this->id, 'user');
@@ -874,7 +889,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
'identifier' => 'commondata'
];
}
- if (Config::get()->VOTE_ENABLE && ($activeVotes || $stoppedVotes || $activeEvals) && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['votes'])) {
+ if (Config::get()->VOTE_ENABLE && ($activeVotes || $stoppedVotes) && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['votes'])) {
$homepage_elements['votes'] = [
'name' => _('Fragebögen'),
'visibility' => $homepage_visibility['votes'] ?? get_default_homepage_visibility($this->id),
@@ -1174,7 +1189,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
// Restliche Daten übertragen
// ForumsModule migrieren
- foreach (PluginEngine::getPlugins('ForumModule') as $plugin) {
+ foreach (PluginEngine::getPlugins(ForumModule::class) as $plugin) {
$plugin->migrateUser($old_id, $new_id);
}
@@ -1211,20 +1226,6 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
$statement = DBManager::get()->prepare($query);
$statement->execute([$new_id, $old_id]);
- // Evaluationen
- $query = "UPDATE IGNORE eval SET author_id = ? WHERE author_id = ?";
- $statement = DBManager::get()->prepare($query);
- $statement->execute([$new_id, $old_id]);
-
- self::removeDoubles('eval_user', 'eval_id', $new_id, $old_id);
- $query = "UPDATE IGNORE eval_user SET user_id = ? WHERE user_id = ?";
- $statement = DBManager::get()->prepare($query);
- $statement->execute([$new_id, $old_id]);
-
- $query = "UPDATE IGNORE evalanswer_user SET user_id = ? WHERE user_id = ?";
- $statement = DBManager::get()->prepare($query);
- $statement->execute([$new_id, $old_id]);
-
// Kategorien
$query = "UPDATE IGNORE kategorien SET range_id = ? WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
@@ -1621,4 +1622,29 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\
return '';
}
}
+
+ /*
+ * Returns whether the user has the given permission (for the given range).
+ *
+ * @param string $permission
+ * @param Range|null $for_range
+ *
+ * @return bool
+ */
+ public function hasPermissionLevel(string $permission, ?Range $for_range = null): bool
+ {
+ if (func_num_args() === 1) {
+ return $GLOBALS['perm']->have_perm($permission, $this->id);
+ }
+
+ if ($for_range === null) {
+ throw new Exception('No valid range given');
+ }
+
+ if ($for_range instanceof User) {
+ return $GLOBALS['perm']->have_profile_perm($permission, $for_range->id, $this->id);
+ }
+
+ return $GLOBALS['perm']->have_studip_perm($permission, $for_range->id, $this->id);
+ }
}
diff --git a/lib/models/UserInfo.class.php b/lib/models/UserInfo.php
index 28808a2..62a63fc 100644
--- a/lib/models/UserInfo.class.php
+++ b/lib/models/UserInfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * UserInfo.class.php
+ * UserInfo.php
* model class for table user_info
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/UserOnline.class.php b/lib/models/UserOnline.php
index e18322d..c3efba2 100644
--- a/lib/models/UserOnline.class.php
+++ b/lib/models/UserOnline.php
@@ -1,7 +1,7 @@
<?php
/**
- * UserOnline.class.php
+ * UserOnline.php
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -24,4 +24,4 @@ class UserOnline extends SimpleORMap
$config['db_table'] = 'user_online';
parent::configure($config);
}
-} \ No newline at end of file
+}
diff --git a/lib/models/UserStudyCourse.class.php b/lib/models/UserStudyCourse.php
index cac37c8..aeac38b 100644
--- a/lib/models/UserStudyCourse.class.php
+++ b/lib/models/UserStudyCourse.php
@@ -1,6 +1,6 @@
<?php
/**
- * UserStudyCourse.class.php
+ * UserStudyCourse.php
* model class for table user_studiengang
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/Vote.php b/lib/models/Vote.php
index 0520401..b5cd142 100644
--- a/lib/models/Vote.php
+++ b/lib/models/Vote.php
@@ -1,6 +1,4 @@
<?php
-require_once 'lib/classes/QuestionType.interface.php';
-
/**
* @license GPL2 or any later version
*
@@ -53,7 +51,7 @@ class Vote extends QuestionnaireQuestion implements QuestionType
public function getDisplayTemplate()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/vote/vote_answer');
$template->set_attribute('vote', $this);
return $template;
@@ -100,7 +98,7 @@ class Vote extends QuestionnaireQuestion implements QuestionType
}
}
}
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views'));
$template = $factory->open('questionnaire/question_types/vote/vote_evaluation');
$template->set_attribute('vote', $this);
$template->set_attribute('answers', $answers);
@@ -113,28 +111,49 @@ class Vote extends QuestionnaireQuestion implements QuestionType
$output = [];
$options = $this['questiondata']['options'] ? $this['questiondata']['options']->getArrayCopy() : [];
+ $multiplechoice = (bool) $this['questiondata']['multiplechoice'];
+
+ if ($multiplechoice) {
+ foreach ($options as $key => $option) {
+ $answerOption = [];
+ $countNobodys = 0;
+
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+
+ if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
+ $userId = $answer['user_id'];
+ } else {
+ $countNobodys++;
+ $userId = _('unbekannt') . ' ' . $countNobodys;
+ }
+
+ if (in_array($key, (array) $answerData['answers'])) {
+ $answerOption[$userId] = 1;
+ } else {
+ $answerOption[$userId] = 0;
+ }
+ }
+ $output[$option] = $answerOption;
+ }
+ } else {
- foreach ($options as $key => $option) {
$answerOption = [];
$countNobodys = 0;
foreach ($this->answers as $answer) {
$answerData = $answer['answerdata']->getArrayCopy();
- if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
+ if ($answer['user_id'] && $answer['user_id'] !== 'nobody') {
$userId = $answer['user_id'];
} else {
- $countNobodys++;
- $userId = _('unbekannt').' '.$countNobodys;
- }
-
- if (in_array($key, (array) $answerData['answers'])) {
- $answerOption[$userId] = 1;
- } else {
- $answerOption[$userId] = 0;
+ $userId = _('unbekannt') . ' ' . ++$countNobodys;
}
+ $answerOption[$userId] = $options[$answerData['answers']];
}
- $output[$option] = $answerOption;
+
+ $question = strip_tags($this['questiondata']['description']);
+ $output[$question] = $answerOption;
}
return $output;
}
diff --git a/lib/models/WebserviceAccessRule.class.php b/lib/models/WebserviceAccessRule.php
index 48da0ef..120ac47 100644
--- a/lib/models/WebserviceAccessRule.class.php
+++ b/lib/models/WebserviceAccessRule.php
@@ -1,6 +1,6 @@
<?php
/**
- * WebserviceAccessRule.class.php
+ * WebserviceAccessRule.php
* model class for table webservice_access_rules
* this class represents one record of the table webservice_access_rules
* the column ip_range is converted from a comma separated list to an ArrayObject and vice-versa,
diff --git a/lib/models/WikiPage.class.php b/lib/models/WikiPage.php
index d349aa1..b5f0101 100644
--- a/lib/models/WikiPage.class.php
+++ b/lib/models/WikiPage.php
@@ -1,6 +1,6 @@
<?php
/**
- * WikiPage.class.php
+ * WikiPage.php
* model class for table wiki
*
* This program is free software; you can redistribute it and/or
@@ -92,7 +92,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
protected function createVersion()
{
- $this->user_id = User::findCurrent()->id;
+ $last_version = $this->versions[0];
if (
!$this->isNew()
&& $this->content['content'] !== $this->content_db['content']
@@ -100,6 +100,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
$this->content_db['user_id'] !== $this->content['user_id']
|| $this->content_db['chdate'] < time() - 60 * 30
)
+ && (!$last_version || $last_version['content'] !== $this['content'])
) {
//Neue Version anlegen:
WikiVersion::create([
diff --git a/lib/models/calendar/CalendarCourseDate.class.php b/lib/models/calendar/CalendarCourseDate.class.php
deleted file mode 100644
index 49179bd..0000000
--- a/lib/models/calendar/CalendarCourseDate.class.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * CalendarCourseDate is a specialisation of CourseDate for
- * course dates that are displayed in the personal calendar.
- */
-class CalendarCourseDate extends CourseDate
-{
- public static function getEvents(DateTime $begin, DateTime $end, string $range_id): array
- {
- return parent::findBySQL(
- "JOIN `seminar_user`
- ON `seminar_user`.`seminar_id` = `termine`.`range_id`
- WHERE `seminar_user`.`user_id` = :user_id
- AND `seminar_user`.`bind_calendar` = '1'
- AND `termine`.`date` BETWEEN :begin AND :end
- AND (
- IFNULL(`termine`.`metadate_id`, '') = ''
- OR `termine`.`metadate_id` NOT IN (
- SELECT `metadate_id`
- FROM `schedule_seminare`
- WHERE `user_id` = :user_id
- AND `visible` = 0
- )
- )
- ORDER BY date",
- [
- 'begin' => $begin->getTimestamp(),
- 'end' => $end->getTimestamp(),
- 'user_id' => $range_id
- ]
- );
- }
-}
diff --git a/lib/models/calendar/CalendarCourseDate.php b/lib/models/calendar/CalendarCourseDate.php
new file mode 100644
index 0000000..370dcd1
--- /dev/null
+++ b/lib/models/calendar/CalendarCourseDate.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * CalendarCourseDate is a specialisation of CourseDate for
+ * course dates that are displayed in the personal calendar.
+ */
+class CalendarCourseDate extends CourseDate
+{
+ public static function getEvents(DateTime $begin, DateTime $end, string $range_id): array
+ {
+ $events = [];
+ parent::findEachBySQL(
+ function ($e) use (&$events, $range_id) {
+ if (self::checkRelated($e, $range_id)) {
+ $events[] = $e;
+ }
+ },
+ "JOIN `seminar_user`
+ ON `seminar_user`.`seminar_id` = `termine`.`range_id`
+ WHERE `seminar_user`.`user_id` = :user_id
+ AND `seminar_user`.`bind_calendar` = '1'
+ AND `termine`.`date` BETWEEN :begin AND :end
+ AND (
+ IFNULL(`termine`.`metadate_id`, '') = ''
+ OR `termine`.`metadate_id` NOT IN (
+ SELECT `metadate_id`
+ FROM `schedule_seminare`
+ WHERE `user_id` = :user_id
+ AND `visible` = 0
+ )
+ )
+ ORDER BY date",
+ [
+ 'begin' => $begin->getTimestamp(),
+ 'end' => $end->getTimestamp(),
+ 'user_id' => $range_id
+ ]
+ );
+ return $events;
+ }
+
+ /**
+ * Checks if given user is the responsible lecturer or is member of a
+ * related group.
+ *
+ * @global object $perm The global perm object.
+ * @param CalendarCourseDate $event The course event to check against.
+ * @param string $user_id The id of the user.
+ * @return boolean
+ */
+ protected static function checkRelated(CalendarCourseDate $event, string $user_id): bool
+ {
+ $check_related = false;
+ $permission = $GLOBALS['perm']->get_studip_perm($event->range_id, $user_id);
+ switch ($permission) {
+ case 'dozent' :
+ $related_persons = $event->dozenten->pluck('user_id');
+ if (count($related_persons) > 0) {
+ $check_related = in_array($user_id, $related_persons);
+ } else {
+ $check_related = true;
+ }
+ break;
+ case 'tutor' :
+ $check_related = true;
+ break;
+ default :
+ $group_ids = $event->statusgruppen->pluck('statusgruppe_id');
+ if (count($group_ids) > 0) {
+ $member = StatusgruppeUser::findBySQL(
+ 'statusgruppe_id IN(?) AND user_id = ?',
+ [$group_ids, $user_id]);
+ $check_related = count($member) > 0;
+ } else {
+ $check_related = true;
+ }
+ }
+ return $check_related;
+ }
+}
diff --git a/lib/models/calendar/CalendarCourseExDate.class.php b/lib/models/calendar/CalendarCourseExDate.php
index eb23aeb..eb23aeb 100644
--- a/lib/models/calendar/CalendarCourseExDate.class.php
+++ b/lib/models/calendar/CalendarCourseExDate.php
diff --git a/lib/models/calendar/CalendarDate.class.php b/lib/models/calendar/CalendarDate.php
index e9269c6..0318dab 100644
--- a/lib/models/calendar/CalendarDate.class.php
+++ b/lib/models/calendar/CalendarDate.php
@@ -1,6 +1,6 @@
<?php
/**
- * CalendarDate.class.php - Model class for calendar dates.
+ * CalendarDate.php - Model class for calendar dates.
*
* CalendarDate represents a date in the personal calendar.
*
@@ -114,7 +114,7 @@ class CalendarDate extends SimpleORMap implements PrivacyObject
public function cbSendDateModificationMail()
{
- $template_factory = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
+ $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
foreach ($this->calendars as $calendar) {
if ($calendar->range_id === $this->editor_id) {
@@ -402,8 +402,8 @@ class CalendarDate extends SimpleORMap implements PrivacyObject
$sorm = self::findThru($storage->user_id, [
'thru_table' => 'calendar_date_assignments',
'thru_key' => 'range_id',
- 'thru_assoc_key' => 'event_id',
- 'assoc_foreign_key' => 'event_id',
+ 'thru_assoc_key' => 'calendar_date_id',
+ 'assoc_foreign_key' => 'id',
]);
if ($sorm) {
$field_data = [];
diff --git a/lib/models/calendar/CalendarDateAssignment.class.php b/lib/models/calendar/CalendarDateAssignment.php
index fbd21a7..e0e2135 100644
--- a/lib/models/calendar/CalendarDateAssignment.class.php
+++ b/lib/models/calendar/CalendarDateAssignment.php
@@ -1,6 +1,6 @@
<?php
/**
- * CalendarDateAssignment.class.php - Model class for calendar date assignments.
+ * CalendarDateAssignment.php - Model class for calendar date assignments.
*
* CalendarDateAssignment represents the assignment of a calendar date
* to a specific calendar. The calendar is represented by a range-ID
@@ -79,7 +79,7 @@ class CalendarDateAssignment extends SimpleORMap implements Event
return;
}
- $template_factory = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
+ $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
setTempLanguage($this->range_id);
$lang_path = getUserLanguagePath($this->range_id);
@@ -112,7 +112,7 @@ class CalendarDateAssignment extends SimpleORMap implements Event
return;
}
- $template_factory = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
+ $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
setTempLanguage($this->range_id);
$lang_path = getUserLanguagePath($this->range_id);
@@ -160,7 +160,7 @@ class CalendarDateAssignment extends SimpleORMap implements Event
return;
}
- $template_factory = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
+ $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/');
setTempLanguage($this->range_id);
$lang_path = getUserLanguagePath($this->range_id);
@@ -250,7 +250,7 @@ class CalendarDateAssignment extends SimpleORMap implements Event
]);
- $sql_repetition = $sql . " AND `calendar_dates`.`begin` < :end AND `calendar_dates`.`repetition_type` IN ('DAYLY', 'WEEKLY', 'MONTHLY', 'YEARLY')
+ $sql_repetition = $sql . " AND `calendar_dates`.`begin` < :end AND `calendar_dates`.`repetition_type` IN ('DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY')
AND `calendar_dates`.`repetition_end` > :begin
";
diff --git a/lib/models/calendar/CalendarDateException.class.php b/lib/models/calendar/CalendarDateException.php
index b53a728..b53a728 100644
--- a/lib/models/calendar/CalendarDateException.class.php
+++ b/lib/models/calendar/CalendarDateException.php
diff --git a/lib/models/resources/BrokenResource.class.php b/lib/models/resources/BrokenResource.php
index 5266b4f..fc44e82 100644
--- a/lib/models/resources/BrokenResource.class.php
+++ b/lib/models/resources/BrokenResource.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceLabel.class.php - model class for a resource label
+ * ResourceLabel.php - model class for a resource label
*
* The BrokenResource class represents resources whose class
* cannot be found due to missing Resource specialisations
diff --git a/lib/models/resources/Building.class.php b/lib/models/resources/Building.php
index 0edb983..a1c071a 100644
--- a/lib/models/resources/Building.class.php
+++ b/lib/models/resources/Building.php
@@ -1,7 +1,7 @@
<?php
/**
- * Building.class.php - model class for a resource which is a building
+ * Building.php - model class for a resource which is a building
*
* The building class is a derived class from the Resource class
* which includes specialisations for Building resource types.
diff --git a/lib/models/resources/GlobalResourceLock.class.php b/lib/models/resources/GlobalResourceLock.php
index b1753f5..ed748e1 100644
--- a/lib/models/resources/GlobalResourceLock.class.php
+++ b/lib/models/resources/GlobalResourceLock.php
@@ -1,7 +1,7 @@
<?php
/**
- * GlobalResourceLock.class.php - model class for resource locks
+ * GlobalResourceLock.php - model class for resource locks
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/resources/Location.class.php b/lib/models/resources/Location.php
index 8e79382..9da2e11 100644
--- a/lib/models/resources/Location.class.php
+++ b/lib/models/resources/Location.php
@@ -1,7 +1,7 @@
<?php
/**
- * Location.class.php - model class for a resource which is a location
+ * Location.php - model class for a resource which is a location
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/resources/Resource.class.php b/lib/models/resources/Resource.php
index 531bc4c..32fce2b 100644
--- a/lib/models/resources/Resource.class.php
+++ b/lib/models/resources/Resource.php
@@ -1,7 +1,7 @@
<?php
/**
- * Resource.class.php - model class for a resource
+ * Resource.php - model class for a resource
*
* The Resource class is the base class of the new
* Room and Resource management system in Stud.IP.
@@ -2296,29 +2296,14 @@ class Resource extends SimpleORMap implements StudipItem
return 'admin';
}
- //Check for a temporary permission first:
$perm_string = '';
$temp_perm = null;
$begin = time();
$end = $begin;
-
- //If $time range is set and contains two DateTime objects
- //we can include that in the search for temporary permissions.
- if ($time_range) {
- if ($time_range[0] instanceof DateTime) {
- $begin = $time_range[0]->getTimestamp();
- } else {
- $begin = $time_range[0];
- }
- if ($time_range[1] instanceof DateTime) {
- $end = $time_range[1]->getTimestamp();
- } else {
- $end = $time_range[1];
- }
- }
-
+ //Check for a temporary permission first:
+ //check only against current timestamp
if (!$permanent_only) {
$temp_perm = ResourceTemporaryPermission::findOneBySql(
'(resource_id = :resource_id) AND (user_id = :user_id)
@@ -2375,8 +2360,18 @@ class Resource extends SimpleORMap implements StudipItem
$perm_string = $global_perm;
}
//Now we must check for global resource locks:
-
if ($perm_string && $time_range && $this->lockable) {
+
+ if ($time_range[0] instanceof DateTime) {
+ $begin = $time_range[0]->getTimestamp();
+ } else {
+ $begin = $time_range[0];
+ }
+ if ($time_range[1] instanceof DateTime) {
+ $end = $time_range[1]->getTimestamp();
+ } else {
+ $end = $time_range[1];
+ }
if (GlobalResourceLock::isLocked($begin, $end)) {
//A permission level exists for the user.
//The user gets "user" permissions in case
diff --git a/lib/models/resources/ResourceBooking.class.php b/lib/models/resources/ResourceBooking.php
index f55b3b3..977cf32 100644
--- a/lib/models/resources/ResourceBooking.class.php
+++ b/lib/models/resources/ResourceBooking.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceBooking.class.php - model class for resource bookings
+ * ResourceBooking.php - model class for resource bookings
*
* The ResourceBooking class is responsible for storing
* bookings of resources in a specified time range
@@ -876,7 +876,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen
$deleted_c = 0;
- $template_factory = new Flexi_TemplateFactory(
+ $template_factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
@@ -1755,18 +1755,16 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen
//(lib/resources.js, method dropEventInRoomGroupBookingPlan)
$interval_api_urls = [
'resize' => \URLHelper::getURL(
- 'api.php/resources/booking/'
- . $this->id . '/move',
+ 'dispatch.php/resources/ajax/move_booking/' . $this->id,
[
- 'quiet' => '1',
+ 'quiet' => true,
'interval_id' => $interval->id
]
),
'move' => \URLHelper::getURL(
- 'api.php/resources/booking/'
- . $this->id . '/move',
+ 'dispatch.php/resources/ajax/move_booking/' . $this->id,
[
- 'quiet' => '1',
+ 'quiet' => true,
'interval_id' => $interval->id
]
)
@@ -1784,11 +1782,11 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen
$text_colour,
$colour,
$booking_is_editable,
- 'ResourceBookingInterval',
+ ResourceBookingInterval::class,
$interval->id,
- 'ResourceBooking',
+ ResourceBooking::class,
$this->id,
- 'Resource',
+ Resource::class,
$this->resource_id,
$booking_view_urls,
$interval_api_urls,
@@ -1917,7 +1915,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen
return;
}
- $template_factory = new Flexi_TemplateFactory(
+ $template_factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
setTempLanguage($booking_user->id);
diff --git a/lib/models/resources/ResourceBookingInterval.class.php b/lib/models/resources/ResourceBookingInterval.php
index 7908e40..47f01cc 100644
--- a/lib/models/resources/ResourceBookingInterval.class.php
+++ b/lib/models/resources/ResourceBookingInterval.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceBookingInterval.class.php - model class for storing
+ * ResourceBookingInterval.php - model class for storing
* all resource bookings time intervals, including those for
* repetitions.
*
diff --git a/lib/models/resources/ResourceCategory.class.php b/lib/models/resources/ResourceCategory.php
index f4ae14d..cfe323a 100644
--- a/lib/models/resources/ResourceCategory.class.php
+++ b/lib/models/resources/ResourceCategory.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceCategory.class.php - model class for resource categories
+ * ResourceCategory.php - model class for resource categories
*
* The ResourceCategory class can be used as a Factory for
* Resource objects.
@@ -85,7 +85,7 @@ class ResourceCategory extends SimpleORMap
public static function find($id)
{
$all = self::findAll();
- return $all[$id] ?: null;
+ return $all[$id] ?? null;
}
/**
diff --git a/lib/models/resources/ResourceCategoryProperty.class.php b/lib/models/resources/ResourceCategoryProperty.php
index b1460cd..c9ac66e 100644
--- a/lib/models/resources/ResourceCategoryProperty.class.php
+++ b/lib/models/resources/ResourceCategoryProperty.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceCategoryProperty.class.php - model class for
+ * ResourceCategoryProperty.php - model class for
* resource category properties
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/resources/ResourceLabel.class.php b/lib/models/resources/ResourceLabel.php
index d9c869f..c465723 100644
--- a/lib/models/resources/ResourceLabel.class.php
+++ b/lib/models/resources/ResourceLabel.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceLabel.class.php - model class for a resource label
+ * ResourceLabel.php - model class for a resource label
*
* The ResourceLabel class represents headings or subheadings whose
* only purpose is helping with organising the resource tree.
diff --git a/lib/models/resources/ResourcePermission.class.php b/lib/models/resources/ResourcePermission.php
index bd33708..044db83 100644
--- a/lib/models/resources/ResourcePermission.class.php
+++ b/lib/models/resources/ResourcePermission.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourcePermission.class.php - model class for resource permissions.
+ * ResourcePermission.php - model class for resource permissions.
*
* Description of the resources permission system:
* - admin: An admin may do everything in the resource management:
diff --git a/lib/models/resources/ResourceProperty.class.php b/lib/models/resources/ResourceProperty.php
index 4bbc4ec..4f7a329 100644
--- a/lib/models/resources/ResourceProperty.class.php
+++ b/lib/models/resources/ResourceProperty.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceProperty.class.php - model class for resource properties
+ * ResourceProperty.php - model class for resource properties
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/resources/ResourcePropertyDefinition.class.php b/lib/models/resources/ResourcePropertyDefinition.php
index 82d29c9..b87e8e6 100644
--- a/lib/models/resources/ResourcePropertyDefinition.class.php
+++ b/lib/models/resources/ResourcePropertyDefinition.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourcePropertyDefinition.class.php - model class for resource property definitions
+ * ResourcePropertyDefinition.php - model class for resource property definitions
*
* The ResourcePropertyDefinition class can be used as a Factory
* for ResourceProperty objects.
@@ -221,7 +221,7 @@ class ResourcePropertyDefinition extends SimpleORMap
);
}
} elseif ($type === 'position') {
- $factory = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH']);
+ $factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH']);
$template = $factory->open('templates/resources/position_attribute_form_part.php');
$template->set_attribute(
'input_name',
diff --git a/lib/models/resources/ResourcePropertyGroup.class.php b/lib/models/resources/ResourcePropertyGroup.php
index ad53902..f6ea825 100644
--- a/lib/models/resources/ResourcePropertyGroup.class.php
+++ b/lib/models/resources/ResourcePropertyGroup.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourcePropertyGroup.class.php - model class for resource property groups
+ * ResourcePropertyGroup.php - model class for resource property groups
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/resources/ResourceRequest.class.php b/lib/models/resources/ResourceRequest.php
index 6b22b44..df77b19 100644
--- a/lib/models/resources/ResourceRequest.class.php
+++ b/lib/models/resources/ResourceRequest.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceRequest.class.php - Contains a model class for resource requests.
+ * ResourceRequest.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
@@ -1963,7 +1963,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
return;
}
- $factory = new Flexi_TemplateFactory(
+ $factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
@@ -2020,7 +2020,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
*/
public function sendCloseRequestMailToRequester($bookings = [])
{
- $factory = new Flexi_TemplateFactory(
+ $factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
@@ -2110,7 +2110,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
);
if ($lecturers) {
- $factory = new Flexi_TemplateFactory(
+ $factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
@@ -2199,7 +2199,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
}
//Load the mail template:
- $factory = new Flexi_TemplateFactory(
+ $factory = new Flexi\Factory(
$GLOBALS['STUDIP_BASE_PATH'] . '/locale/'
);
$user_lang_path = getUserLanguagePath($user->id);
@@ -2244,24 +2244,19 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
protected function convertToEventData(array $time_intervals, User $user)
{
- $booking_plan_request_bg =
- ColourValue::find('Resources.BookingPlan.Request.Bg');
- $booking_plan_request_fg =
- ColourValue::find('Resources.BookingPlan.Request.Fg');
- $booking_plan_preparation_bg =
- ColourValue::find('Resources.BookingPlan.PreparationTime.Bg');
- $booking_plan_preparation_fg =
- ColourValue::find('Resources.BookingPlan.PreparationTime.Fg');
+ $booking_plan_request_bg = ColourValue::find('Resources.BookingPlan.Request.Bg');
+ $booking_plan_request_fg = ColourValue::find('Resources.BookingPlan.Request.Fg');
+ $booking_plan_preparation_bg = ColourValue::find('Resources.BookingPlan.PreparationTime.Bg');
+ $booking_plan_preparation_fg = ColourValue::find('Resources.BookingPlan.PreparationTime.Fg');
$user_is_resource_autor = false;
- if ($this->resource_id && ($this->resource instanceof Resource)) {
+ if ($this->resource_id && $this->resource instanceof Resource) {
$user_is_resource_autor = $this->resource->userHasPermission(
$user,
'autor'
);
}
- $request_is_editable =
- $user_is_resource_autor || ($user->id == $this->user_id);
+ $request_is_editable = $user_is_resource_autor || ($user->id == $this->user_id);
$request_api_urls = [];
$request_view_urls = [];
@@ -2269,18 +2264,12 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
if ($request_is_editable) {
$request_api_urls = [
'resize' => URLHelper::getURL(
- 'api.php/resources/request/'
- . $this->id . '/move',
- [
- 'quiet' => '1'
- ]
+ 'dispatch.php/resources/ajax/move_request/'. $this->id,
+ ['quiet' => true]
),
- 'move' => URLHelper::getURL(
- 'api.php/resources/request/'
- . $this->id . '/move',
- [
- 'quiet' => '1'
- ]
+ 'move' => URLHelper::getURL(
+ 'dispatch.php/resources/ajax/move_request/'. $this->id,
+ ['quiet' => true]
)
];
@@ -2290,13 +2279,14 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
. $this->id
)
];
- if ($this->resource_id && ($this->resource instanceof Resource)) {
- if ($this->resource->userHasBookingRights($user)) {
- $request_view_urls['edit'] = URLHelper::getURL(
- 'dispatch.php/resources/room_request/resolve/'
- . $this->id
- );
- }
+ if (
+ $this->resource_id
+ && $this->resource instanceof Resource
+ && $this->resource->userHasBookingRights($user)
+ ) {
+ $request_view_urls['edit'] = URLHelper::getURL(
+ 'dispatch.php/resources/room_request/resolve/'. $this->id
+ );
}
}
@@ -2306,7 +2296,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
$real_begin = $interval['begin'];
if ($this->preparation_time) {
$real_begin += (int)$this->preparation_time;
- $begin = new DateTime();
+ $begin = new DateTime();
$begin->setTimestamp($interval['begin']);
$end = new DateTime();
$end->setTimestamp($real_begin);
@@ -2320,9 +2310,9 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
$request_is_editable,
'',
'',
- 'ResourceRequest',
+ ResourceRequest::class,
$this->id,
- 'Resource',
+ Resource::class,
$this->resource_id,
$request_view_urls,
$request_api_urls
@@ -2342,11 +2332,11 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
$booking_plan_request_fg->__toString(),
$booking_plan_request_bg->__toString(),
$request_is_editable,
- 'ResourceRequest',
+ ResourceRequest::class,
$this->id,
- 'Resource',
+ Resource::class,
$this->resource_id,
- 'Resource',
+ Resource::class,
$this->resource_id,
$request_view_urls,
$request_api_urls
diff --git a/lib/models/resources/ResourceRequestAppointment.class.php b/lib/models/resources/ResourceRequestAppointment.php
index 929733b..63384a2 100644
--- a/lib/models/resources/ResourceRequestAppointment.class.php
+++ b/lib/models/resources/ResourceRequestAppointment.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceRequestAppointment.class.php - Contains a model class for
+ * ResourceRequestAppointment.php - Contains a model class for
* the resource_request_appointments table.
*
* ResourceRequestAppointment is a model class to connect
diff --git a/lib/models/resources/ResourceRequestProperty.class.php b/lib/models/resources/ResourceRequestProperty.php
index 2952be9..c387daa 100644
--- a/lib/models/resources/ResourceRequestProperty.class.php
+++ b/lib/models/resources/ResourceRequestProperty.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceRequestProperty.class.php - model class for
+ * ResourceRequestProperty.php - model class for
* resource request properties
*
* This program is free software; you can redistribute it and/or
diff --git a/lib/models/resources/ResourceTemporaryPermission.class.php b/lib/models/resources/ResourceTemporaryPermission.php
index ddbc397..ad7b33a 100644
--- a/lib/models/resources/ResourceTemporaryPermission.class.php
+++ b/lib/models/resources/ResourceTemporaryPermission.php
@@ -1,7 +1,7 @@
<?php
/**
- * ResourceTemporaryPermission.class.php
+ * ResourceTemporaryPermission.php
* Contains the ResourceTemporaryPermission class
*
* The ResourceTemporaryPermission class represents temporary permissions
diff --git a/lib/models/resources/Room.class.php b/lib/models/resources/Room.php
index 7f1668e..c8e393c 100644
--- a/lib/models/resources/Room.class.php
+++ b/lib/models/resources/Room.php
@@ -1,7 +1,7 @@
<?php
/**
- * Room.class.php - model class for a resource which is a room
+ * Room.php - model class for a resource which is a room
*
* The Room class is a derived class of the Resource class.
* It containts specialisations for room resources.
diff --git a/lib/models/resources/RoomRequest.class.php b/lib/models/resources/RoomRequest.php
index 6db9c38..4ba11bc 100644
--- a/lib/models/resources/RoomRequest.class.php
+++ b/lib/models/resources/RoomRequest.php
@@ -1,7 +1,7 @@
<?php
/**
- * RoomRequest.class.php - model class for table resource_requests
+ * RoomRequest.php - model class for table 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
diff --git a/lib/models/resources/SeparableRoom.class.php b/lib/models/resources/SeparableRoom.php
index 9ec1ccf..d1bf125 100644
--- a/lib/models/resources/SeparableRoom.class.php
+++ b/lib/models/resources/SeparableRoom.php
@@ -1,7 +1,7 @@
<?php
/**
- * SeparableRoom.class.php - model class for a separable room
+ * SeparableRoom.php - model class for a separable room
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/lib/models/resources/SeparableRoomPart.class.php b/lib/models/resources/SeparableRoomPart.php
index e7e99e7..8a45ce7 100644
--- a/lib/models/resources/SeparableRoomPart.class.php
+++ b/lib/models/resources/SeparableRoomPart.php
@@ -1,7 +1,7 @@
<?php
/**
- * SeparableRoomItem.class.php - model class for a separable room item
+ * SeparableRoomItem.php - model class for a separable room item
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as