diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php index 996ad87a60440556ef686db226388637240fc1ed..8216924637ec1504a7a7a46079269b1972fe7ce6 100644 --- a/app/controllers/my_courses.php +++ b/app/controllers/my_courses.php @@ -90,7 +90,7 @@ class MyCoursesController extends AuthenticatedController 'order' => 'asc', 'studygroups_enabled' => Config::get()->MY_COURSES_ENABLE_STUDYGROUPS, 'deputies_enabled' => Config::get()->DEPUTIES_ENABLE, - ]); + ]) ?? []; // Waiting list $this->waiting_list = MyRealmModel::getWaitingList($GLOBALS['user']->id); @@ -182,25 +182,26 @@ class MyCoursesController extends AuthenticatedController $this->current_semester = $sem ?: Semester::findCurrent()->semester_id; $this->semesters = Semester::findAllVisible(); - $forced_grouping = Config::get()->MY_COURSES_FORCE_GROUPING; - if ($forced_grouping == 'not_grouped') { - $forced_grouping = 'sem_number'; - } - - $no_grouping_allowed = ($forced_grouping == 'sem_number' || !in_array($forced_grouping, getValidGroupingFields())); - - $group_field = $GLOBALS['user']->cfg->MY_COURSES_GROUPING ? : $forced_grouping; + $group_field = $this->getGroupField(); $groups = []; $add_fields = ''; $add_query = ''; - if ($group_field == 'sem_tree_id') { + if ($group_field === 'sem_tree_id') { $add_fields = ', sem_tree_id'; $add_query = "LEFT JOIN seminar_sem_tree sst ON (sst.seminar_id=seminare.Seminar_id)"; - } else if ($group_field == 'dozent_id') { + } elseif ($group_field === 'dozent_id') { $add_fields = ', su1.user_id as dozent_id'; $add_query = "LEFT JOIN seminar_user as su1 ON (su1.seminar_id=seminare.Seminar_id AND su1.status='dozent')"; + } elseif ($group_field === 'mvv') { + $add_fields = ', mm.`modul_id` AS mvv'; + $add_query = "LEFT JOIN `mvv_lvgruppe_seminar` AS mls ON (mls.`seminar_id` = seminare.`Seminar_id`) + LEFT JOIN `mvv_lvgruppe` AS ml ON (mls.`lvgruppe_id` = ml.`lvgruppe_id`) + LEFT JOIN `mvv_lvgruppe_modulteil` AS mlm on(mls.`lvgruppe_id` = mlm.`lvgruppe_id`) + LEFT JOIN `mvv_modulteil` AS mmt ON (mlm.`modulteil_id` = mmt.`modulteil_id`) + LEFT JOIN `mvv_modul` AS mm ON (mmt.`modul_id` = mm.`modul_id`)"; + } $dbv = DbView::getView('sem_tree'); @@ -229,7 +230,7 @@ class MyCoursesController extends AuthenticatedController $query .= " ORDER BY sem_nr ASC"; $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, studygroup_sem_types()]); + $statement->execute([$GLOBALS['user']->id]); while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { $my_sem[$row['Seminar_id']] = [ 'obj_type' => 'sem', @@ -276,12 +277,11 @@ class MyCoursesController extends AuthenticatedController } } $this->studygroups = $studygroups; - $this->no_grouping_allowed = $no_grouping_allowed; $this->groups = $groups; $this->group_names = get_group_names($group_field, $groups); $this->group_field = $group_field; $this->my_sem = $my_sem; - $this->cid = Request::get('cid') ? Request::get('cid') : ''; + $this->cid = Request::get('cid', ''); } /** @@ -712,8 +712,22 @@ class MyCoursesController extends AuthenticatedController * * @param array $sem_courses * @param string $group_field + * @return array{ + * courses: array, + * groups: array, + * user_id: string, + * config: array{ + * allow_dozent_visibility: bool, + * open_groups: array, + * sem_number: bool, + * display_type: string, + * responsive_type: string, + * navigation_show_only_new: bool, + * group_by: string + * } + * } */ - private function getMyCoursesData($sem_courses, $group_field) + private function getMyCoursesData(array $sem_courses, string $group_field): array { $sem_data = Semester::getAllAsArray(); $temp_courses = []; @@ -813,6 +827,11 @@ class MyCoursesController extends AuthenticatedController 'gruppe' => _('Farbgruppen'), 'dozent_id' => _('Lehrende'), ]; + + if (LvgruppeSeminar::countBySql('1') > 0) { + $groups['mvv'] = _('Modul'); + } + $views = Sidebar::get()->addWidget(new ViewsWidget()); $views->setTitle(_('Gruppierung')); foreach ($groups as $key => $group) { diff --git a/app/views/my_courses/groups.php b/app/views/my_courses/groups.php index c562d97db8e9fb1ca8a408e3f35ee586b2365730..22628c524350b94392e82b4fde7e30f1afb560e6 100644 --- a/app/views/my_courses/groups.php +++ b/app/views/my_courses/groups.php @@ -1,4 +1,16 @@ -<form method="post" action="<?= $controller->link_for('my_courses/store_groups/'.$studygroups) ?>" class="default"> +<?php +/** + * @var MyCoursesController $controller + * @var bool $studygroups + * @var string $cid + * @var array $groups + * @var array $group_names + * @var array $semesters + * @var string $group_field + * @var string $current_semester + */ +?> +<form method="post" action="<?= $controller->store_groups($studygroups) ?>" class="default"> <?= CSRFProtection::tokenTag() ?> <input type="hidden" name="cid" value="<?= htmlReady($cid) ?>"> @@ -24,9 +36,9 @@ <th colspan="10" class="toggle-indicator"> <a class="toggler" href="#"> <? if (is_array($group_names[$group_id])): ?> - <?= htmlReady(my_substr($group_names[$group_id][1] . ' > ' . $group_names[$group_id][0], 0, 70)) ?> + <?= htmlReady($group_names[$group_id][1] . ' > ' . $group_names[$group_id][0]) ?> <? else: ?> - <?= htmlReady(my_substr($group_names[$group_id], 0, 70)) ?> + <?= htmlReady($group_names[$group_id]) ?> <? endif; ?> </a> </th> diff --git a/lib/classes/MyRealmModel.php b/lib/classes/MyRealmModel.php index 35232620f859ba3701d4a927da8706b7b1d2a79d..ce5694221bea437225fad48e9dc788221bde0126 100644 --- a/lib/classes/MyRealmModel.php +++ b/lib/classes/MyRealmModel.php @@ -333,8 +333,8 @@ class MyRealmModel // get teachers only if grouping selected (for better performance) if ($group_field === 'dozent_id') { $teachers = new SimpleCollection($course->getMembersWithStatus('dozent')); - $teachers->filter(function ($a) use (&$_course) { - return $_course['teachers'][] = $a->user->getFullName('no_title_rev'); + $_course['teachers'] = $teachers->map(function (CourseMember $a) { + return $a->user->getFullName('no_title_rev'); }); } @@ -344,7 +344,7 @@ class MyRealmModel $_course['gruppe'] = !$is_deputy ? $member_ships[$course->id]['gruppe'] ?? null : ($deputy ? $deputy->gruppe : null); $_course['sem_number_end'] = $course->isOpenEnded() ? $max_sem_key : Semester::getIndexById($course->end_semester->id); $_course['sem_number'] = Semester::getIndexById($course->start_semester->id); - $_course['tools'] = $course->tools; + $_course['tools'] = $course->tools; $_course['name'] = $course->name; $_course['temp_name'] = $course->name; $_course['number'] = $course->veranstaltungsnummer; @@ -439,6 +439,11 @@ class MyRealmModel self::groupBySemTree($sem_courses); } + // Group by mvv module + if ($group_field === 'mvv') { + self::groupByMVVModule($sem_courses); + } + return $sem_courses ?: null; } @@ -771,9 +776,41 @@ class MyRealmModel ksort($_tmp_courses[$sem_key]); } } + $sem_courses = $_tmp_courses; } + /** + * Groups the list of courses by associated mvv module of the course.. + * + * @param array $sem_courses + */ + public static function groupByMVVModule(array &$sem_courses): void + { + $_tmp_courses = []; + foreach ($sem_courses as $sem_key => $collection) { + $_tmp_courses[$sem_key] = []; + foreach ($collection as $course) { + $modules = Course::getMVVModulesForCourseId($course['seminar_id']); + if ($modules) { + $modules = array_map(function (Modul $module) { + return $module->getDisplayName(); + }, $modules); + } else { + $modules = [_('Keinem Modul zugeordnet')]; + } + + foreach ($modules as $module) { + if (!isset($_tmp_courses[$sem_key][$module])) { + $_tmp_courses[$sem_key][$module] = []; + } + $_tmp_courses[$sem_key][$module][$course['seminar_id']] = $course; + } + } + ksort($_tmp_courses[$sem_key]); + } + $sem_courses = $_tmp_courses; + } /** * Retrieves all study groups for the current user. diff --git a/lib/meine_seminare_func.inc.php b/lib/meine_seminare_func.inc.php index f2b49d7da534f8c02a8ec35f1f8fda2734fed978..28cb23b8726db7de49eecc824aae00489b1497e9 100644 --- a/lib/meine_seminare_func.inc.php +++ b/lib/meine_seminare_func.inc.php @@ -6,85 +6,86 @@ /** * - * @param unknown_type $group_field - * @param unknown_type $groups + * @param string $group_field + * @param array $groups */ -function get_group_names($group_field, $groups) +function get_group_names(string $group_field, array $groups): array { - global $SEM_TYPE, $SEM_CLASS; - $groupcount = 1; - if ($group_field == 'sem_tree_id') { - $the_tree = TreeAbstract::GetInstance("StudipSemTree", ["build_index" => true]); - } - if ($group_field == 'sem_number') { + $mapper = function (): string { + return 'unknown'; + }; + if ($group_field === 'sem_number') { $all_semester = Semester::findAllVisible(); - } - foreach ($groups as $key => $value) { - switch ($group_field){ - case 'sem_number': - $ret[$key] = (string) $all_semester[$key]['name']; - break; - - case 'sem_tree_id': - if ($the_tree->tree_data[$key]) { - //$ret[$key] = $the_tree->getShortPath($key); - $ret[$key][0] = $the_tree->tree_data[$key]['name']; - $ret[$key][1] = $the_tree->getShortPath($the_tree->tree_data[$key]['parent_id']); - } else { - //$ret[$key] = _("keine Studienbereiche eingetragen"); - $ret[$key][0] = _("keine Studienbereiche eingetragen"); - $ret[$key][1] = ''; + $mapper = function ($key) use ($all_semester): string { + return (string) $all_semester[$key]['name']; + }; + } elseif ($group_field === 'sem_tree_id') { + $the_tree = TreeAbstract::GetInstance(StudipSemTree::class, ['build_index' => true]); + $mapper = function ($key) use ($the_tree): string { + if (!empty($the_tree->tree_data[$key])) { + return implode(' > ', array_filter([ + $the_tree->getShortPath($the_tree->tree_data[$key]['parent_id']), + $the_tree->tree_data[$key]['name'], + ])); } - break; - case 'sem_status': - $ret[$key] = $SEM_TYPE[$key]["name"]." (". $SEM_CLASS[$SEM_TYPE[$key]["class"]]["name"].")"; - break; - - case 'not_grouped': - $ret[$key] = _("keine Gruppierung"); - break; - - case 'gruppe': - $ret[$key] = _("Gruppe")." ".$groupcount; - $groupcount++; - break; - - case 'dozent_id': - $ret[$key] = get_fullname($key, 'no_title_short'); - break; + return _('keine Studienbereiche eingetragen'); + }; + } elseif ($group_field === 'sem_status') { + $mapper = function ($key): string { + $sem_type = $GLOBALS['SEM_TYPE'][$key]; + return "{$sem_type['name']} ({$GLOBALS['SEM_CLASS'][$sem_type['class']]['name']})"; + }; + } elseif ($group_field === 'no_grouped') { + $mapper = function (): string { + return _('keine Gruppierung'); + }; + } elseif ($group_field === 'gruppe') { + $groupcount = 0; + $mapper = function () use (&$groupcount): string { + $groupcount += 1; + return _('Gruppe') . " {$groupcount}"; + }; + } elseif ($group_field === 'dozent_id') { + $mapper = function ($key): string { + return get_fullname($key, 'no_title_short'); + }; + } elseif ($group_field === 'mvv') { + $mapper = function ($key): string { + $module = Modul::find($key); + return $module ? (string) $module->getDisplayName() : _('Keinem Modul zugeordnet'); + }; + } - default: - $ret[$key] = 'unknown'; - break; - } + $result = []; + foreach (array_keys($groups) as $key) { + $result[$key] = $mapper($key); } - return $ret; + return $result; } /** * - * @param unknown_type $group_field - * @param unknown_type $groups + * @param string $group_field + * @param array $groups */ function sort_groups($group_field, &$groups) { - switch ($group_field){ - + switch ($group_field) { case 'sem_number': krsort($groups, SORT_NUMERIC); - break; + break; case 'gruppe': ksort($groups, SORT_NUMERIC); - break; + break; case 'sem_tree_id': uksort($groups, function ($a, $b) { $the_tree = TreeAbstract::GetInstance('StudipSemTree', ['build_index' => true]); return $the_tree->tree_data[$a]['index'] - $the_tree->tree_data[$b]['index']; }); - break; + break; case 'sem_status': uksort($groups, function ($a, $b) { @@ -106,10 +107,23 @@ function sort_groups($group_field, &$groups) }); break; - default: + case 'mvv': + uksort($groups, function ($a, $b): int { + $module_a = Modul::find($a); + $module_b = Modul::find($b); + + if (!$module_a) { + return 1; + } + if (!$module_b) { + return -1; + } + return strnatcasecmp($module_a->getDisplayName(), $module_b->getDisplayName()); + }); + break; } - foreach ($groups as $key => $value) { + foreach ($groups as $key => &$value) { usort($value, function ($a, $b) { if ($a['gruppe'] != $b['gruppe']) { return (int)($a['gruppe'] - $b['gruppe']); @@ -121,17 +135,16 @@ function sort_groups($group_field, &$groups) } } }); - $groups[$key] = $value; } return true; } /** * - * @param unknown_type $groups - * @param unknown_type $my_obj + * @param array $groups + * @param array $my_obj */ -function correct_group_sem_number(&$groups, &$my_obj) +function correct_group_sem_number(&$groups, &$my_obj): bool { if (is_array($groups) && is_array($my_obj)) { $sem_data = Semester::findAllVisible(); @@ -139,7 +152,9 @@ function correct_group_sem_number(&$groups, &$my_obj) //$max_sem = key($sem_data); foreach ($sem_data as $sem_key => $one_sem){ $current_sem = $sem_key; - if (!$one_sem['past']) break; + if (!$one_sem['past']) { + break; + } } if (isset($sem_data[$current_sem + 1])){ $max_sem = $current_sem + 1; @@ -151,7 +166,9 @@ function correct_group_sem_number(&$groups, &$my_obj) if ($values['sem_number_end'] == -1 && $values['sem_number'] < $current_sem) { unset($groups[$values['sem_number']][$seminar_id]); fill_groups($groups, $current_sem, ['seminar_id' => $seminar_id, 'name' => $values['name'], 'gruppe' => $values['gruppe']]); - if (!count($groups[$values['sem_number']])) unset($groups[$values['sem_number']]); + if (!count($groups[$values['sem_number']])) { + unset($groups[$values['sem_number']]); + } } else { $to_sem = $values['sem_number_end']; for ($i = $values['sem_number']; $i <= $to_sem; ++$i){ @@ -172,9 +189,9 @@ function correct_group_sem_number(&$groups, &$my_obj) /** * - * @param unknown_type $my_obj + * @param mixed $my_obj */ -function add_sem_name(&$my_obj) +function add_sem_name(&$my_obj): bool { if ($GLOBALS['user']->cfg->getValue('SHOWSEM_ENABLE')) { $sem_data = Semester::findAllVisible(); @@ -195,11 +212,13 @@ function add_sem_name(&$my_obj) /** * - * @param array $groups - * @param string $group_key - * @param array $group_entry + * @param array $groups + * @param string|null $group_key + * @param array $group_entry + * + * @return bool */ -function fill_groups(&$groups, $group_key, $group_entry) +function fill_groups(array &$groups, ?string $group_key, array $group_entry): bool { if (is_null($group_key)){ $group_key = 'not_grouped'; @@ -210,16 +229,16 @@ function fill_groups(&$groups, $group_key, $group_entry) } $group_entry['name'] = str_replace( - ["ä","ö","ü"], - ["ae","oe","ue"], + ['ä', 'ö', 'ü'], + ['ae', 'oe', 'ue'], mb_strtolower($group_entry['name']) ); if (!in_array($group_entry, $groups[$group_key])) { $groups[$group_key][$group_entry['seminar_id']] = $group_entry; return true; - } else { - return false; } + + return false; } /** @@ -228,14 +247,20 @@ function fill_groups(&$groups, $group_key, $group_entry) * * @return array All fields that may be specified for course grouping */ -function getValidGroupingFields() +function getValidGroupingFields(): array { - return [ + $valid = [ 'not_grouped', 'sem_number', 'sem_tree_id', 'sem_status', 'gruppe', - 'dozent_id' + 'dozent_id', ]; + + if (LvgruppeSeminar::countBySql('1') > 0) { + $valid[] = 'mvv'; + } + + return $valid; } diff --git a/lib/models/Course.class.php b/lib/models/Course.class.php index 2d485490fc2481d1d7c3f0d6a2e4b1d74038b0db..86e9a471c53bc796be826dfc3c1036a28e25e351 100644 --- a/lib/models/Course.class.php +++ b/lib/models/Course.class.php @@ -288,6 +288,27 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return null; } + + /** + * Returns the associated mvv modules for a given course id. + * + * @param string $course_id + * @return Modul[] + */ + public static function getMVVModulesForCourseId(string $course_id): 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`) + WHERE seminar_id = ?"; + return DBManager::get()->fetchAll($query, [$course_id], function ($row) { + return Modul::buildExisting($row); + }); + } + public function getEnd_Time() { return $this->duration_time == -1 ? -1 : $this->start_time + $this->duration_time; @@ -1030,7 +1051,6 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return array_filter($this->tools->getStudipModule()); } - /** * @see Range::__toString() */