diff options
| author | Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de> | 2026-02-18 16:56:50 +0100 |
|---|---|---|
| committer | Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de> | 2026-02-18 16:56:50 +0100 |
| commit | db42e7dbb81076ec7de59d5c3d0d66fc7c9cb3f2 (patch) | |
| tree | f77b940d1f16c5da0f02f619b6fb94e5ec0ca46e /lib | |
| parent | 93ab04fdc51ae681ff2d4ec9774d2b44244ea2f2 (diff) | |
reimplement SemClass and SemType as SORM classes, fixes #2785tic-2785
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/classes/JsonApi/Schemas/SemType.php | 2 | ||||
| -rw-r--r-- | lib/classes/SemClass.php | 638 | ||||
| -rw-r--r-- | lib/classes/SemType.php | 257 | ||||
| -rw-r--r-- | lib/classes/coursewizardsteps/BasicDataWizardStep.php | 6 | ||||
| -rw-r--r-- | lib/models/Course.php | 2 | ||||
| -rw-r--r-- | lib/models/SemClass.php | 375 | ||||
| -rw-r--r-- | lib/models/SemType.php | 133 |
7 files changed, 513 insertions, 900 deletions
diff --git a/lib/classes/JsonApi/Schemas/SemType.php b/lib/classes/JsonApi/Schemas/SemType.php index 46b2e3c..20312e0 100644 --- a/lib/classes/JsonApi/Schemas/SemType.php +++ b/lib/classes/JsonApi/Schemas/SemType.php @@ -31,7 +31,7 @@ class SemType extends SchemaProvider $relationships = []; // SemClass - $related = $resource->getClass(); + $related = $resource->getSemClass(); $relationships[self::REL_SEM_CLASS] = [ self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->createLinkToResource($related) diff --git a/lib/classes/SemClass.php b/lib/classes/SemClass.php deleted file mode 100644 index 5e20af5..0000000 --- a/lib/classes/SemClass.php +++ /dev/null @@ -1,638 +0,0 @@ -<?php - -/* - * Copyright (c) 2012 Rasmus Fuhse <fuhse@data-quest.de> - * - * 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. - */ - -/** - * Class to define and manage attributes of seminar classes (or seminar categories). - * Usually all sem-classes are stored in a global variable $SEM_CLASS which is - * an array of SemClass objects. - * - * SemClass::getClasses() gets you all seminar classes in an array. - * - * You can access the attributes of a sem-class like an associative - * array with $sem_class['default_read_level']. The uinderlying data is stored - * in the database in the table sem_classes. - * - * If you want to have a name of a sem-class like "Lehre", please use - * $sem_class['name'] and you will get a fully localized name and not the pure - * database entry. - * - * This class manages also which modules are contained in which course-slots, - * like "what module is used as a forum in my seminars". In the database stored - * is the name of the module like "CoreForum" or a classname of a plugin or null - * if the forum is completely disabled by root for this sem-class. Core-modules - * can only be used within a standard slot. Plugins may also be used as optional - * modules not contained in a slot. - * - * In the field 'modules' in the database is for each modules stored in a json-string - * if the module is activatable by the teacher or not and if it is activated as - * a default. Please use the methods SemClass::isSlotModule, SemClass::getSlotModule, - * SemClass::isModuleAllowed, SemClass::isModuleMandatory, SemClass::isSlotMandatory - * or even more simple SemClass::getNavigationForSlot (see documentation there). - */ -class SemClass implements ArrayAccess -{ - protected $data = []; - - static protected $studygroup_forbidden_modules = [ - 'CoreAdmin', - 'CoreParticipants', - ]; - - static protected $sem_classes = null; - - static public function getDefaultSemClass() { - $data = [ - 'name' => "Fehlerhafte Seminarklasse!", - 'modules' => '{"CoreOverview":{"activated":1,"sticky":1},"CoreAdmin":{"activated":1,"sticky":1}}', - 'visible' => 1, - 'is_group' => false - ]; - return new SemClass($data); - } - - /** - * Generates a dummy SemClass for institutes of this type (as defined in config.inc.php). - * @param integer $type institute type - * @return SemClass - */ - static public function getDefaultInstituteClass($type) - { - global $INST_MODULES; - - // fall back to 'default' if modules are not defined - $type = isset($INST_MODULES[$type]) ? $type : 'default'; - - $data = [ - 'name' => _('Generierte Standardinstitutsklasse'), - 'visible' => 1, - 'admin' => 'CoreAdmin', // always available - 'overview' => 'CoreOverview' // always available - ]; - $slots = [ - 'forum' => 'CoreForum', - 'documents' => 'CoreDocuments', - 'scm' => 'CoreScm', - 'wiki' => 'CoreWiki', - 'calendar' => 'CoreCalendar', - 'elearning_interface' => 'CoreElearningInterface', - 'personal' => 'CorePersonal' - ]; - $modules = [ - 'CoreAdmin' => ['activated' => 1, 'sticky' => 1], - 'CoreOverview' => ['activated' => 1, 'sticky' => 1], - ]; - - foreach ($slots as $slot => $module) { - $data[$slot] = $module; - $modules[$module] = ['activated' => (int) ($INST_MODULES[$type][$slot] ?? 0), 'sticky' => 0]; - } - $data['modules'] = json_encode($modules); - - return new SemClass($data); - } - - /** - * Constructor can be set with integer of sem_class_id or an array of - * the old $SEM_CLASS style. - * @param integer | array $data - */ - public function __construct($data) - { - $db = DBManager::get(); - if (is_int($data)) { - $statement = $db->prepare("SELECT * FROM sem_classes WHERE id = :id "); - $statement->execute(['id' => $data]); - $this->data = $statement->fetch(PDO::FETCH_ASSOC); - } else { - $this->data = $data; - } - if (!empty($this->data['modules'])) { - $this->data['modules'] = self::object2array(json_decode($this->data['modules'])); - - } else { - $this->data['modules'] = []; - } - if (!empty($this->data['studygroup_mode'])) { - if (!isset($this->data['modules']['CoreStudygroupAdmin'])) { - $this->data['modules']['CoreStudygroupAdmin'] = ['activated' => 1, 'sticky' => 1]; - } - } else { - if (!isset($this->data['modules']['CoreAdmin'])) { - $this->data['modules']['CoreAdmin'] = ['activated' => 1, 'sticky' => 1]; - } - } - foreach (array_keys($this->data['modules']) as $modulename) { - if ($this->isModuleForbidden($modulename)) { - unset($this->data['modules'][$modulename]); - } - } - } - - - /** - * @param string $module - * @return false|int - */ - public function activateModuleInCourses($module) - { - $plugin = PluginManager::getInstance()->getPlugin($module); - if ($plugin) { - return Course::findEachBySQL(function ($course) use ($plugin) { - return PluginManager::getInstance()->setPluginActivated($plugin->getPluginId(), $course->id, true); - }, - "seminare.status IN (?)", - [array_keys($this->getSemTypes())]); - } else { - return false; - } - } - - /** - * @param string $module - * @return false|int - */ - public function deActivateModuleInCourses($module) - { - $plugin = PluginManager::getInstance()->getPlugin($module); - if ($plugin) { - return Course::findEachBySQL(function ($course) use ($plugin) { - return PluginManager::getInstance()->setPluginActivated($plugin->getPluginId(), $course->id, false); - }, - "seminare.status IN (?)", - [array_keys($this->getSemTypes())]); - } else { - return false; - } - - } - - /** - * Returns the number of seminars of this sem_class in Stud.IP - * @return integer - */ - public function countSeminars() - { - $db = DBManager::get(); - $sum = 0; - foreach ($GLOBALS['SEM_TYPE'] as $sem_type) { - if ($sem_type['class'] == $this->data['id']) { - $sum += $sem_type->countSeminars(); - } - } - return $sum; - } - - - /** - * @param string $modulename - * @return bool - */ - public function isModuleForbidden($modulename) - { - if (!empty($this->data['studygroup_mode'])) { - return in_array($modulename, self::$studygroup_forbidden_modules); - } else { - return strpos($modulename, 'Studygroup') !== false; - } - } - - /** - * Returns the metadata of a module regarding this sem_class object. - * @param string $modulename - * @return array('sticky' => (bool), 'activated' => (bool)) - */ - public function getModuleMetadata($modulename) - { - return $this->data['modules'][$modulename]; - } - - /** - * Sets the metadata for each module at once. - * @param array $module_array: array($module_name => array('sticky' => (bool), 'activated' => (bool)), ...) - */ - public function setModules($module_array) - { - $this->data['modules'] = $module_array; - } - - /** - * Returns all metadata of the modules at once. - * @return array: array($module_name => array('sticky' => (bool), 'activated' => (bool)), ...) - */ - public function getModules() - { - return $this->data['modules']; - } - - /** - * @return StudipModule[] - */ - public function getModuleObjects() - { - $result = []; - foreach (array_keys($this->getModules()) as $module) { - $plugin = PluginManager::getInstance()->getPlugin($module); - if ($plugin) { - $result[$plugin->getPluginId()] = $plugin; - } - } - return $result; - } - - /** - * @return string[] - */ - public function getActivatedModules() - { - return array_keys(array_filter($this->data['modules'], function ($meta) { - return $meta['activated']; - })); - } - - /** - * @return StudipModule[] - */ - public function getActivatedModuleObjects() - { - $result = []; - foreach ($this->getActivatedModules() as $module) { - $plugin = PluginManager::getInstance()->getPlugin($module); - if ($plugin) { - $result[$plugin->getPluginId()] = $plugin; - } - } - return $result; - } - - /** - * @return mixed|object - */ - public function getAdminModuleObject() - { - if ($this->data['studygroup_mode']) { - $module = 'CoreStudygroupAdmin'; - } else { - $module = 'CoreAdmin'; - } - return PluginManager::getInstance()->getPlugin($module); - } - - /** - * Returns true if a module is activated on default for this sem_class. - * @param string $modulename - * @return boolean - */ - public function isModuleActivated($modulename) - { - return isset($this->data['modules'][$modulename]) - && $this->data['modules'][$modulename]['activated']; - } - - /** - * Returns if a module is allowed to be displayed for this sem_class. - * @param string $modulename - * @return boolean - */ - public function isModuleAllowed($modulename) - { - return !$this->isModuleForbidden($modulename) - && ( - empty($this->data['modules'][$modulename]) - || empty($this->data['modules'][$modulename]['sticky']) - || !empty($this->data['modules'][$modulename]['activated']) - ); - } - - /** - * Returns if a module is mandatory for this sem_class. - * @param string $module - * @return boolean - */ - public function isModuleMandatory($module) - { - return isset($this->data['modules'][$module]) - && !empty($this->data['modules'][$module]['sticky']) - && !empty($this->data['modules'][$module]['activated']); - } - - public function getSemTypes() - { - $types = []; - foreach (SemType::getTypes() as $id => $type) { - if ($type['class'] == $this->data['id']) { - $types[$id] = $type; - } - } - return $types; - } - - /** - * Checks if the current sem class is usable for course grouping. - */ - public function isGroup() - { - return $this->data['is_group']; - } - - /** - * Checks if any SemClasses exist that provide grouping functionality. - * @return SimpleCollection - */ - public static function getGroupClasses() - { - return SimpleCollection::createFromArray(self::getClasses())->findBy('is_group', true); - } - - /** - * stores all data in the database - * @return boolean success - */ - public function store() - { - $db = DBManager::get(); - $statement = $db->prepare( - "UPDATE sem_classes " . - "SET name = :name, " . - "description = :description, " . - "create_description = :create_description, " . - "studygroup_mode = :studygroup_mode, " . - "only_inst_user = :only_inst_user, " . - "default_read_level = :default_read_level, " . - "default_write_level = :default_write_level, " . - "bereiche = :bereiche, " . - "module = :module, " . - "show_browse = :show_browse, " . - "visible = :visible, " . - "course_creation_forbidden = :course_creation_forbidden, " . - "modules = :modules, " . - "title_dozent = :title_dozent, " . - "title_dozent_plural = :title_dozent_plural, " . - "title_tutor = :title_tutor, " . - "title_tutor_plural = :title_tutor_plural, " . - "title_autor = :title_autor, " . - "title_autor_plural = :title_autor_plural, " . - "admission_prelim_default = :admission_prelim_default, " . - "admission_type_default = :admission_type_default, " . - "show_raumzeit = :show_raumzeit, " . - "is_group = :is_group, " . - "unlimited_forbidden = :unlimited_forbidden, " . - "admission_turnout_mandatory = :admission_turnout_mandatory," . - "chdate = UNIX_TIMESTAMP() " . - "WHERE id = :id ". - ""); - \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY'); - return $statement->execute([ - 'id' => $this->data['id'], - 'name' => $this->data['name'], - 'description' => $this->data['description'], - 'create_description' => $this->data['create_description'], - 'studygroup_mode' => (int) $this->data['studygroup_mode'], - 'only_inst_user' => (int) $this->data['only_inst_user'], - 'default_read_level' => (int) $this->data['default_read_level'], - 'default_write_level' => (int) $this->data['default_write_level'], - 'bereiche' => (int) $this->data['bereiche'], - 'module' => (int) $this->data['module'], - 'show_browse' => (int) $this->data['show_browse'], - 'visible' => (int) $this->data['visible'], - 'course_creation_forbidden' => (int) $this->data['course_creation_forbidden'], - 'modules' => json_encode((object) $this->data['modules']), - 'title_dozent' => $this->data['title_dozent'] - ? $this->data['title_dozent'] - : null, - 'title_dozent_plural' => $this->data['title_dozent_plural'] - ? $this->data['title_dozent_plural'] - : null, - 'title_tutor' => $this->data['title_tutor'] - ? $this->data['title_tutor'] - : null, - 'title_tutor_plural' => $this->data['title_tutor_plural'] - ? $this->data['title_tutor_plural'] - : null, - 'title_autor' => $this->data['title_autor'] - ? $this->data['title_autor'] - : null, - 'title_autor_plural' => $this->data['title_autor_plural'] - ? $this->data['title_autor_plural'] - : null, - 'admission_prelim_default' => (int)$this->data['admission_prelim_default'], - 'admission_type_default' => (int)$this->data['admission_type_default'], - 'show_raumzeit' => (int) $this->data['show_raumzeit'], - 'is_group' => (int) $this->data['is_group'], - 'unlimited_forbidden' => (int) $this->data['unlimited_forbidden'], - 'admission_turnout_mandatory' => (int) $this->data['admission_turnout_mandatory'], - ]); - } - - /** - * Deletes the sem_class-object and all its sem_types. Will only delete, - * if there are no seminars in this sem_class. - * Remember to refresh the global $SEM_CLASS and $SEM_TYPE array. - * @return boolean : success of deletion - */ - public function delete() - { - if ($this->countSeminars() === 0) { - foreach ($GLOBALS['SEM_TYPE'] as $sem_type) { - if ($sem_type['class'] == $this->data['id']) { - $sem_type->delete(); - } - } - $GLOBALS['SEM_TYPE'] = SemType::getTypes(); - $db = DBManager::get(); - $statement = $db->prepare(" - DELETE FROM sem_classes - WHERE id = :id - "); - \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY'); - return $statement->execute([ - 'id' => $this->data['id'] - ]); - } else { - return false; - } - } - - /** - * Sets an attribute of sem_class->data - * @param string $offset - * @param mixed $value - */ - public function set($offset, $value) - { - $this->data[$offset] = $value; - } - - /*************************************************************************** - * ArrayAccess methods * - ***************************************************************************/ - - /** - * deprecated, does nothing, should not be used - * @param string $offset - * @param mixed $value - */ - public function offsetSet($offset, $value): void - { - } - - /** - * Compatibility function with old $SEM_CLASS variable for plugins. Maps the - * new array-structure to the old boolean values. - * @param integer $offset: name of attribute - */ - public function offsetGet($offset): mixed - { - switch ($offset) { - case "name": - return gettext($this->data['name']); - case "only_inst_user": - return (bool) $this->data['only_inst_user']; - case "bereiche": - return (bool) $this->data['bereiche']; - case "show_browse": - return (bool) $this->data['show_browse']; - case "visible": - return (bool) $this->data['visible']; - case "studygroup_mode": - return (bool) $this->data['studygroup_mode']; - case "admission_prelim_default": - return (int) $this->data['admission_prelim_default']; - case "admission_type_default": - return (int) $this->data['admission_type_default']; - case "is_group": - return (bool) $this->data['is_group']; - } - //ansonsten - return $this->data[$offset] ?? null; - } - - /** - * ArrayAccess method to check if an attribute exists. - * @param int $offset - */ - public function offsetExists($offset): bool - { - return isset($this->data[$offset]); - } - - /** - * deprecated, does nothing, should not be used - * @param string $offset - */ - public function offsetUnset($offset): void - { - } - - /*************************************************************************** - * static methods * - ***************************************************************************/ - - /** - * Returns an array of all SemClasses in Stud.IP. Equivalent to global - * $SEM_CLASS variable. This variable is statically stored in this class. - * @return SemClass[] of SemClass - */ - static public function getClasses() - { - if (!is_array(self::$sem_classes)) { - $db = DBManager::get(); - self::$sem_classes = []; - - $cache = \Studip\Cache\Factory::getCache(); - $class_array = unserialize($cache->read('DB_SEM_CLASSES_ARRAY')); - if (!$class_array) { - - try { - $statement = $db->prepare( - "SELECT * FROM sem_classes ORDER BY id ASC " - ); - $statement->execute(); - $class_array = $statement->fetchAll(PDO::FETCH_ASSOC); - - if ($class_array) { - $cache = \Studip\Cache\Factory::getCache(); - $cache->write('DB_SEM_CLASSES_ARRAY', serialize($class_array)); - } - } catch (PDOException $e) { - //for use without or before migration 92 - $class_array = $GLOBALS['SEM_CLASS_OLD_VAR']; - if (is_array($class_array)) { - ksort($class_array); - foreach ($class_array as $id => $class) { - self::$sem_classes[$id] = new SemClass($class); - } - } else { - self::$sem_classes[1] = self::getDefaultSemClass(); - } - } - } - foreach ($class_array as $sem_class) { - self::$sem_classes[$sem_class['id']] = new SemClass($sem_class); - } - } - return self::$sem_classes; - } - - /** - * Refreshes the internal $sem_classes cache-variable. - * @return array of SemClass - */ - static public function refreshClasses() - { - \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY'); - self::$sem_classes = null; - return self::getClasses(); - } - - /** - * Static method to recursively transform an object into an associative array. - * @param mixed $obj: should be of class StdClass - * @return array - */ - static public function object2array($obj) - { - $arr_raw = is_object($obj) ? get_object_vars($obj) : $obj; - foreach ($arr_raw as $key => $val) { - $val = (is_array($val) || is_object($val)) ? self::object2array($val) : $val; - $arr[$key] = $val; - } - return $arr; - } - - - /** - * Static method only to keep the translationstrings of the values. It is - * never used within the system. - */ - static private function localization() - { - _("Lehre"); - _("Forschung"); - _("Organisation"); - _("Community"); - _("Arbeitsgruppen"); - _("importierte Kurse"); - _("Hauptveranstaltungen"); - - _("Hier finden Sie alle in Stud.IP registrierten Lehrveranstaltungen"); - _("Verwenden Sie diese Kategorie, um normale Lehrveranstaltungen anzulegen"); - _("Hier finden Sie virtuelle Veranstaltungen zum Thema Forschung an der Universität"); - _("In dieser Kategorie können Sie virtuelle Veranstaltungen für Forschungsprojekte anlegen."); - _("Hier finden Sie virtuelle Veranstaltungen zu verschiedenen Gremien an der Universität"); - _("Um virtuelle Veranstaltungen für Uni-Gremien anzulegen, verwenden Sie diese Kategorie"); - _("Hier finden Sie virtuelle Veranstaltungen zu unterschiedlichen Themen"); - _("Wenn Sie Veranstaltungen als Diskussiongruppen zu unterschiedlichen Themen anlegen möchten, verwenden Sie diese Kategorie."); - _("Hier finden Sie verschiedene Arbeitsgruppen an der %s"); - _("Verwenden Sie diese Kategorie, um unterschiedliche Arbeitsgruppen anzulegen."); - _("Veranstaltungen dieser Kategorie dienen als Gruppierungselement, um die Zusammengehörigkeit von Veranstaltungen anderer Kategorien abzubilden."); - } - -} diff --git a/lib/classes/SemType.php b/lib/classes/SemType.php deleted file mode 100644 index 5be1f19..0000000 --- a/lib/classes/SemType.php +++ /dev/null @@ -1,257 +0,0 @@ -<?php - -/* - * Copyright (c) 2012 Rasmus Fuhse <fuhse@data-quest.de> - * - * 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. - */ - -if (isset($GLOBALS['SEM_TYPE'])) { - $GLOBALS['SEM_TYPE_OLD_VAR'] = $GLOBALS['SEM_TYPE']; -} - -/** - * Class to define and manage attributes of seminar types. - * Usually all sem-types are stored in a global variable $SEM_TYPE which is - * an array of SemType objects. - * - * SemType::getTypes() gets you all seminar types in an array. - * - * This class only represents the name of the type and gives a relation to a - * sem_class. - */ -class SemType implements ArrayAccess -{ - protected $data = []; - static protected $sem_types = null; - - /** - * Constructor can be set with integer of sem_class_id or an array of - * the old $SEM_CLASS style. - * @param integer | array $data - */ - public function __construct($data) { - $db = DBManager::get(); - if (is_int($data)) { - $statement = $db->prepare("SELECT * FROM sem_types WHERE id = :id "); - $statement->execute(['id' => $data]); - $this->data = $statement->fetch(PDO::FETCH_ASSOC); - } else { - $this->data = $data; - } - } - - /** - * Returns the number of seminars of this sem_type in Stud.IP - * @return integer - */ - public function countSeminars() { - $db = DBManager::get(); - $statement = $db->prepare("SELECT COUNT(*) FROM seminare WHERE status = :sem_type "); - $statement->execute(['sem_type' => $this->data['id']]); - return (int) $statement->fetch(PDO::FETCH_COLUMN, 0); - } - - /** - * stores all data in the database - * @return boolean success - */ - public function store() { - $db = DBManager::get(); - $statement = $db->prepare( - "UPDATE sem_types " . - "SET name = :name, " . - "class = :class, " . - "chdate = UNIX_TIMESTAMP() " . - "WHERE id = :id ". - ""); - \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY'); - return $statement->execute([ - 'id' => $this->data['id'], - 'name' => $this->data['name'], - 'class' => $this->data['class'] - ]); - } - - /** - * Deletes the sem_type-object. Will only delete, - * if there are no seminars in this sem_type. - * Remember to refresh the global $SEM_TYPE array. - * @return boolean : success of deletion - */ - public function delete() { - if ($this->countSeminars() === 0) { - $db = DBManager::get(); - $statement = $db->prepare(" - DELETE FROM sem_types - WHERE id = :id - "); - \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY'); - return $statement->execute([ - 'id' => $this->data['id'] - ]); - } else { - return false; - } - } - - /** - * Sets an attribute of sem_type->data - * @param string $offset - * @param mixed $value - */ - public function set($offset, $value) { - $this->data[$offset] = $value; - } - - public function getClass() { - return $GLOBALS['SEM_CLASS'][$this->data['class']] ?? SemClass::getDefaultSemClass(); - } - - /*************************************************************************** - * ArrayAccess methods * - ***************************************************************************/ - - /** - * deprecated, does nothing, should not be used - * @param string $offset - * @param mixed $value - */ - - public function offsetSet($offset, $value): void - { - } - - /** - * Compatibility function with old $SEM_TYPE variable for plugins. Maps the - * new array-structure to the old boolean values. - * @param integer $offset: name of attribute - */ - public function offsetGet($offset): mixed - { - switch ($offset) { - case "name": - return gettext($this->data['name']); - case in_array($offset, ["title_dozent", "title_tutor", "title_autor"]): - $sem_class = $this->getClass(); - $title = [$sem_class[$offset], $sem_class[$offset.'_plural']]; - return $title[0] || $title[1] ? $title : $this->data[$offset]; - } - //ansonsten - return $this->data[$offset]; - } - - /** - * ArrayAccess method to check if an attribute exists. - * @param mixed $offset - */ - public function offsetExists($offset): bool - { - return isset($this->data[$offset]); - } - - /** - * deprecated, does nothing, should not be used - * @param string $offset - */ - public function offsetUnset($offset): void - { - } - - /*************************************************************************** - * static methods * - ***************************************************************************/ - - /** - * Returns an array of all SemTypes in Stud.IP. Equivalent to global - * $SEM_TYPE variable. This variable is statically stored in this class. - * @return array of SemType - */ - static public function getTypes() { - if (!is_array(self::$sem_types)) { - $db = DBManager::get(); - self::$sem_types = []; - - $cache = \Studip\Cache\Factory::getCache(); - $types_array = unserialize($cache->read('DB_SEM_TYPES_ARRAY')); - if (!$types_array) { - try { - $statement = $db->prepare( - "SELECT * FROM sem_types ORDER BY id ASC " - ); - $statement->execute(); - $types_array = $statement->fetchAll(PDO::FETCH_ASSOC); - if ($types_array) { - $cache = \Studip\Cache\Factory::getCache(); - $cache->write('DB_SEM_TYPES_ARRAY', serialize($types_array)); - } - } catch (PDOException $e) { - //for use without or before migration 92 - $type_array = $GLOBALS['SEM_TYPE_OLD_VAR']; - if (is_array($type_array)) { - ksort($type_array); - foreach ($type_array as $id => $type) { - self::$sem_types[$id] = new SemType($type); - } - } else { - self::$sem_types[1] = new SemType(['name' => 'default', 'class' => 1, 'id' => 1]); - } - } - } - foreach ($types_array as $sem_type) { - self::$sem_types[$sem_type['id']] = new SemType($sem_type); - } - } - return self::$sem_types; - } - - static public function refreshTypes() { - self::$sem_types = null; - \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY'); - return self::getTypes(); - } - - /** - * Gets all SemTypes that are allowed as group parents. - * @return array - */ - public static function getGroupingSemTypes() - { - return SimpleCollection::createFromArray(array_flatten(SemClass::getGroupClasses()->getSemTypes()))->pluck('id'); - } - - /** - * Gets all SemTypes that are allowed as group parents. - * @return array - */ - public static function getNonGroupingSemTypes() - { - $non_grouping = SimpleCollection::createFromArray(SemClass::getClasses())->findBy('is_group', false)->findBy('studygroup_mode', false); - return SimpleCollection::createFromArray(array_flatten($non_grouping->getSemTypes()))->pluck('id'); - } - - /** - * Static method only to keep the translationstrings of the values. It is - * never used within the system. - */ - static private function localization() { - _("Vorlesung"); - _("Seminar"); - _("Übung"); - _("Praktikum"); - _("Colloquium"); - _("Kolloquium"); - _("Forschungsgruppe"); - _("sonstige"); - _("Gremium"); - _("Projektgruppe"); - _("Kulturforum"); - _("Veranstaltungsboard"); - _("Studiengruppe"); - - } - -} diff --git a/lib/classes/coursewizardsteps/BasicDataWizardStep.php b/lib/classes/coursewizardsteps/BasicDataWizardStep.php index 2e265c3..35ad6dc 100644 --- a/lib/classes/coursewizardsteps/BasicDataWizardStep.php +++ b/lib/classes/coursewizardsteps/BasicDataWizardStep.php @@ -50,7 +50,7 @@ class BasicDataWizardStep implements CourseWizardStep $typestruct = []; $admission_turnout_mandatory_types = []; foreach (SemType::getTypes() as $type) { - $class = $type->getClass(); + $class = $type->getSemClass(); // Creates a studygroup. if (!empty($values['studygroup'])) { // Get all studygroup types. @@ -385,8 +385,8 @@ class BasicDataWizardStep implements CourseWizardStep $errors[] = _('Sie müssen die Nutzungsbedingungen akzeptieren.'); } } - $sem_type = new SemType((int)$values['coursetype']); - $sem_class = $sem_type->getClass(); + $sem_type = $GLOBALS['SEM_TYPE'][(int)$values['coursetype']]; + $sem_class = $sem_type->getSemClass(); if ($sem_class['admission_turnout_mandatory'] && !$values['maxmembers']) { $errors[] = _('Sie müssen die maximale Teilnehmendenzahl angeben'); } diff --git a/lib/models/Course.php b/lib/models/Course.php index db729c6..7910931 100644 --- a/lib/models/Course.php +++ b/lib/models/Course.php @@ -1827,7 +1827,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe */ public function getSemClass() { - return $this->getSemType()->getClass(); + return $this->getSemType()->getSemClass(); } /** diff --git a/lib/models/SemClass.php b/lib/models/SemClass.php new file mode 100644 index 0000000..6eb2029 --- /dev/null +++ b/lib/models/SemClass.php @@ -0,0 +1,375 @@ +<?php + +/* + * Copyright (c) 2012 Rasmus Fuhse <fuhse@data-quest.de> + * + * 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. + */ + +/** + * Class to define and manage attributes of seminar classes (or seminar categories). + * Usually all sem-classes are stored in a global variable $SEM_CLASS which is + * an array of SemClass objects. + * + * SemClass::getClasses() gets you all seminar classes in an array. + * + * You can access the attributes of a sem-class like an associative + * array with $sem_class['default_read_level']. The uinderlying data is stored + * in the database in the table sem_classes. + * + * If you want to have a name of a sem-class like "Lehre", please use + * $sem_class['name'] and you will get a fully localized name and not the pure + * database entry. + * + * This class manages also which modules are contained in which course-slots, + * like "what module is used as a forum in my seminars". In the database stored + * is the name of the module like "CoreForum" or a classname of a plugin or null + * if the forum is completely disabled by root for this sem-class. Core-modules + * can only be used within a standard slot. Plugins may also be used as optional + * modules not contained in a slot. + * + * In the field 'modules' in the database is for each modules stored in a json-string + * if the module is activatable by the teacher or not and if it is activated as + * a default. Please use the methods SemClass::isSlotModule, SemClass::getSlotModule, + * SemClass::isModuleAllowed, SemClass::isModuleMandatory, SemClass::isSlotMandatory + * or even more simple SemClass::getNavigationForSlot (see documentation there). + */ +class SemClass extends SimpleORMap +{ + static protected $sem_classes = null; + + static protected $studygroup_forbidden_modules = [ + 'CoreAdmin', + 'CoreParticipants', + ]; + + /** + * Configure the database mapping. + */ + protected static function configure($config = []) + { + $config['db_table'] = 'sem_classes'; + + $config['serialized_fields']['modules'] = 'JSONArrayObject'; + + $config['has_many']['sem_types'] = [ + 'class_name' => SemType::class, + 'assoc_foreign_key' => 'class', + 'on_delete' => 'delete' + ]; + + $config['registered_callbacks']['after_store'][] = 'SemClass::refreshClasses'; + $config['registered_callbacks']['after_delete'][] = 'SemClass::refreshClasses'; + + parent::configure($config); + } + + public static function getDefaultSemClass() { + return self::build([ + 'name' => _('Fehlerhafte Seminarklasse'), + 'modules' => [ + 'CoreOverview' => ['activated' => 1, 'sticky' => 1], + 'CoreAdmin' => ['activated' => 1, 'sticky' => 1] + ], + 'visible' => 1, + 'is_group' => false + ]); + } + + /** + * Generates a dummy SemClass for institutes of this type (as defined in config.inc.php). + * @param integer $type institute type + * @return SemClass + */ + public static function getDefaultInstituteClass($type) + { + global $INST_MODULES; + + // fall back to 'default' if modules are not defined + $type = isset($INST_MODULES[$type]) ? $type : 'default'; + + $data = [ + 'name' => _('Generierte Standardinstitutsklasse'), + 'visible' => 1, + 'admin' => 'CoreAdmin', // always available + 'overview' => 'CoreOverview' // always available + ]; + $slots = [ + 'forum' => 'CoreForum', + 'documents' => 'CoreDocuments', + 'scm' => 'CoreScm', + 'wiki' => 'CoreWiki', + 'calendar' => 'CoreCalendar', + 'elearning_interface' => 'CoreElearningInterface', + 'personal' => 'CorePersonal' + ]; + $modules = [ + 'CoreAdmin' => ['activated' => 1, 'sticky' => 1], + 'CoreOverview' => ['activated' => 1, 'sticky' => 1], + ]; + + foreach ($slots as $slot => $module) { + $data[$slot] = $module; + $modules[$module] = ['activated' => (int) ($INST_MODULES[$type][$slot] ?? 0), 'sticky' => 0]; + } + $data['modules'] = $modules; + + return self::build($data); + } + + /** + * @param string $module + * @return false|int + */ + public function activateModuleInCourses($module) + { + $plugin = PluginManager::getInstance()->getPlugin($module); + if ($plugin) { + return Course::findEachBySQL(function ($course) use ($plugin) { + return PluginManager::getInstance()->setPluginActivated($plugin->getPluginId(), $course->id, true); + }, + "seminare.status IN (?)", + [array_keys($this->getSemTypes())]); + } else { + return false; + } + } + + /** + * @param string $module + * @return false|int + */ + public function deActivateModuleInCourses($module) + { + $plugin = PluginManager::getInstance()->getPlugin($module); + if ($plugin) { + return Course::findEachBySQL(function ($course) use ($plugin) { + return PluginManager::getInstance()->setPluginActivated($plugin->getPluginId(), $course->id, false); + }, + "seminare.status IN (?)", + [array_keys($this->getSemTypes())]); + } else { + return false; + } + + } + + /** + * Returns the number of seminars of this sem_class in Stud.IP + * @return integer + */ + public function countSeminars() + { + $sum = 0; + foreach ($this->sem_types as $sem_type) { + $sum += $sem_type->countSeminars(); + } + return $sum; + } + + + /** + * @param string $modulename + * @return bool + */ + public function isModuleForbidden($modulename) + { + if (!empty($this->studygroup_mode)) { + return in_array($modulename, self::$studygroup_forbidden_modules); + } else { + return strpos($modulename, 'Studygroup') !== false; + } + } + + /** + * Returns the metadata of a module regarding this sem_class object. + * @param string $modulename + * @return array('sticky' => (bool), 'activated' => (bool)) + */ + public function getModuleMetadata($modulename) + { + return $this->modules[$modulename]; + } + + /** + * @return StudipModule[] + */ + public function getModuleObjects() + { + $result = []; + foreach (array_keys($this->modules->getArrayCopy()) as $module) { + $plugin = PluginManager::getInstance()->getPlugin($module); + if ($plugin) { + $result[$plugin->getPluginId()] = $plugin; + } + } + return $result; + } + + /** + * @return string[] + */ + public function getActivatedModules() + { + return array_keys(array_filter($this->modules->getArrayCopy(), function ($meta) { + return $meta['activated']; + })); + } + + /** + * @return StudipModule[] + */ + public function getActivatedModuleObjects() + { + $result = []; + foreach ($this->getActivatedModules() as $module) { + $plugin = PluginManager::getInstance()->getPlugin($module); + if ($plugin) { + $result[$plugin->getPluginId()] = $plugin; + } + } + return $result; + } + + /** + * @return mixed|object + */ + public function getAdminModuleObject() + { + if ($this->studygroup_mode) { + $module = 'CoreStudygroupAdmin'; + } else { + $module = 'CoreAdmin'; + } + return PluginManager::getInstance()->getPlugin($module); + } + + /** + * Returns true if a module is activated on default for this sem_class. + * @param string $modulename + * @return boolean + */ + public function isModuleActivated($modulename) + { + return isset($this->modules[$modulename]) + && $this->modules[$modulename]['activated']; + } + + /** + * Returns if a module is allowed to be displayed for this sem_class. + * @param string $modulename + * @return boolean + */ + public function isModuleAllowed($modulename) + { + return !$this->isModuleForbidden($modulename) + && ( + empty($this->modules[$modulename]) + || empty($this->modules[$modulename]['sticky']) + || !empty($this->modules[$modulename]['activated']) + ); + } + + /** + * Returns if a module is mandatory for this sem_class. + * @param string $module + * @return boolean + */ + public function isModuleMandatory($module) + { + return isset($this->modules[$module]) + && !empty($this->modules[$module]['sticky']) + && !empty($this->modules[$module]['activated']); + } + + public function getSemTypes() + { + $types = []; + foreach ($this->sem_types as $type) { + $types[$type->id] = $type; + } + return $types; + } + + /** + * Checks if the current sem class is usable for course grouping. + */ + public function isGroup() + { + return $this->is_group; + } + + /** + * Checks if any SemClasses exist that provide grouping functionality. + * @return SimpleCollection + */ + public static function getGroupClasses() + { + return SimpleCollection::createFromArray(self::getClasses())->findBy('is_group', true); + } + + /** + * Returns an array of all SemClasses in Stud.IP. Equivalent to global + * $SEM_CLASS variable. This variable is statically stored in this class. + * @return SemClass[] of SemClass + */ + public static function getClasses() + { + if (!is_array(self::$sem_classes)) { + $cache = \Studip\Cache\Factory::getCache(); + $class_array = $cache->read('DB_SEM_CLASSES_ARRAY'); + + if (!is_array($class_array)) { + $class_array = self::findBySQL('1 ORDER BY id'); + $cache->write('DB_SEM_CLASSES_ARRAY', $class_array); + } + + foreach ($class_array as $sem_class) { + self::$sem_classes[$sem_class->id] = $sem_class; + } + } + + return self::$sem_classes; + } + + /** + * Refreshes the internal $sem_classes cache-variable. + * @return array of SemClass + */ + public static function refreshClasses() + { + \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY'); + self::$sem_classes = null; + return self::getClasses(); + } + + /** + * Static method only to keep the translationstrings of the values. It is + * never used within the system. + */ + static private function localization() + { + _("Lehre"); + _("Forschung"); + _("Organisation"); + _("Community"); + _("Arbeitsgruppen"); + _("importierte Kurse"); + _("Hauptveranstaltungen"); + + _("Hier finden Sie alle in Stud.IP registrierten Lehrveranstaltungen"); + _("Verwenden Sie diese Kategorie, um normale Lehrveranstaltungen anzulegen"); + _("Hier finden Sie virtuelle Veranstaltungen zum Thema Forschung an der Universität"); + _("In dieser Kategorie können Sie virtuelle Veranstaltungen für Forschungsprojekte anlegen."); + _("Hier finden Sie virtuelle Veranstaltungen zu verschiedenen Gremien an der Universität"); + _("Um virtuelle Veranstaltungen für Uni-Gremien anzulegen, verwenden Sie diese Kategorie"); + _("Hier finden Sie virtuelle Veranstaltungen zu unterschiedlichen Themen"); + _("Wenn Sie Veranstaltungen als Diskussiongruppen zu unterschiedlichen Themen anlegen möchten, verwenden Sie diese Kategorie."); + _("Hier finden Sie verschiedene Arbeitsgruppen an der %s"); + _("Verwenden Sie diese Kategorie, um unterschiedliche Arbeitsgruppen anzulegen."); + _("Veranstaltungen dieser Kategorie dienen als Gruppierungselement, um die Zusammengehörigkeit von Veranstaltungen anderer Kategorien abzubilden."); + } +} diff --git a/lib/models/SemType.php b/lib/models/SemType.php new file mode 100644 index 0000000..4453bb0 --- /dev/null +++ b/lib/models/SemType.php @@ -0,0 +1,133 @@ +<?php + +/* + * Copyright (c) 2012 Rasmus Fuhse <fuhse@data-quest.de> + * + * 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. + */ + +/** + * Class to define and manage attributes of seminar types. + * Usually all sem-types are stored in a global variable $SEM_TYPE which is + * an array of SemType objects. + * + * SemType::getTypes() gets you all seminar types in an array. + * + * This class only represents the name of the type and gives a relation to a + * sem_class. + */ +class SemType extends SimpleORMap +{ + static protected $sem_types = null; + + /** + * Configure the database mapping. + */ + protected static function configure($config = []) + { + $config['db_table'] = 'sem_types'; + + $config['has_many']['courses'] = [ + 'class_name' => Course::class, + 'assoc_foreign_key' => 'status' + ]; + + $config['belongs_to']['sem_class'] = [ + 'class_name' => SemClass::class, + 'foreign_key' => 'class' + ]; + + $config['registered_callbacks']['after_store'][] = 'SemType::refreshTypes'; + $config['registered_callbacks']['after_delete'][] = 'SemType::refreshTypes'; + + parent::configure($config); + } + + /** + * Returns the number of seminars of this sem_type in Stud.IP + * @return integer + */ + public function countSeminars() + { + return Course::countBySql('status = ?', [$this->id]); + } + + public function getSemClass() + { + return $GLOBALS['SEM_CLASS'][$this->class] ?? SemClass::getDefaultSemClass(); + } + + /** + * Returns an array of all SemTypes in Stud.IP. Equivalent to global + * $SEM_TYPE variable. This variable is statically stored in this class. + * @return array of SemType + */ + public static function getTypes() + { + if (!is_array(self::$sem_types)) { + $cache = \Studip\Cache\Factory::getCache(); + $types_array = $cache->read('DB_SEM_TYPES_ARRAY'); + + if (!is_array($types_array)) { + $types_array = self::findBySQL('1 ORDER BY id'); + $cache->write('DB_SEM_TYPES_ARRAY', $types_array); + } + + foreach ($types_array as $sem_type) { + self::$sem_types[$sem_type->id] = $sem_type; + } + } + + return self::$sem_types; + } + + public static function refreshTypes() + { + \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY'); + self::$sem_types = null; + return self::getTypes(); + } + + /** + * Gets all SemTypes that are allowed as group parents. + * @return array + */ + public static function getGroupingSemTypes() + { + return SimpleCollection::createFromArray(array_flatten(SemClass::getGroupClasses()->getSemTypes()))->pluck('id'); + } + + /** + * Gets all SemTypes that are allowed as group parents. + * @return array + */ + public static function getNonGroupingSemTypes() + { + $non_grouping = SimpleCollection::createFromArray(SemClass::getClasses())->findBy('is_group', false)->findBy('studygroup_mode', false); + return SimpleCollection::createFromArray(array_flatten($non_grouping->getSemTypes()))->pluck('id'); + } + + /** + * Static method only to keep the translationstrings of the values. It is + * never used within the system. + */ + static private function localization() + { + _("Vorlesung"); + _("Seminar"); + _("Übung"); + _("Praktikum"); + _("Colloquium"); + _("Kolloquium"); + _("Forschungsgruppe"); + _("sonstige"); + _("Gremium"); + _("Projektgruppe"); + _("Kulturforum"); + _("Veranstaltungsboard"); + _("Studiengruppe"); + } +} |
