diff options
| author | Marcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de> | 2022-01-19 10:25:54 +0000 |
|---|---|---|
| committer | Marcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de> | 2022-01-19 10:25:54 +0000 |
| commit | c706fd9205bb45fd3c902b271c626e68a5fe8a10 (patch) | |
| tree | d7f6647fe667623df6e64d4dbac74104fcc818f4 /app/controllers/course/courseware.php | |
| parent | d62f1b7480c51a290c168c79a6f8ea05757a6e77 (diff) | |
Coursewares Übersichtsseite beschleunigen
Diffstat (limited to 'app/controllers/course/courseware.php')
| -rwxr-xr-x | app/controllers/course/courseware.php | 237 |
1 files changed, 115 insertions, 122 deletions
diff --git a/app/controllers/course/courseware.php b/app/controllers/course/courseware.php index b22ffb7..c4aae64 100755 --- a/app/controllers/course/courseware.php +++ b/app/controllers/course/courseware.php @@ -60,9 +60,9 @@ class Course_CoursewareController extends AuthenticatedController Navigation::activateItem('course/courseware/content'); $this->setIndexSidebar(); - $this->licenses = array(); - $sorm_licenses = License::findBySQL("1 ORDER BY name ASC"); - foreach($sorm_licenses as $license) { + $this->licenses = []; + $sorm_licenses = License::findBySQL('1 ORDER BY name ASC'); + foreach ($sorm_licenses as $license) { array_push($this->licenses, $license->toArray()); } $this->licenses = json_encode($this->licenses); @@ -87,7 +87,6 @@ class Course_CoursewareController extends AuthenticatedController } else { Navigation::activateItem('course/courseware/manager'); } - } private function setIndexSidebar(): void @@ -106,151 +105,145 @@ class Course_CoursewareController extends AuthenticatedController $sidebar->addWidget($views)->addLayoutCSSClass('courseware-view-widget'); } - private function getProgressData(bool $course_progress = false): array + private function getProgressData(bool $showProgressForAllParticipants = false): iterable { - $data = []; + /** @var ?\Course $course */ + $course = Context::get(); + if (!$course || !$course->courseware) { + return []; + } - $cid = Context::getId(); - $course = Course::find($cid); - $course_members = $course->getMembersWithStatus('autor'); - $course_member_ids = array_column($course_members, 'user_id'); + $instance = new Instance($course->courseware); + $user = \User::findCurrent(); - $elements = StructuralElement::findBySQL('range_id = ?', [$cid]); + $elements = $this->findElements($instance, $user); + $progress = $this->computeSelfProgresses($instance, $user, $elements, $showProgressForAllParticipants); + $progress = $this->computeCumulativeProgresses($instance, $elements, $progress); - if ($course_progress) { - $cw_user_progresses = UserProgress::findBySQL('user_id IN (?)', [$course_member_ids]); - } else { - $cw_user_progresses = UserProgress::findBySQL('user_id = ?', [ - $GLOBALS['user']->id, - ]); - } + return $this->prepareProgressData($elements, $progress); + } - foreach ($elements as $element) { - $el = [ - 'id' => $element->id, - 'name' => $element->title, - 'parent_id' => $element->parent->id, - 'parent_name' => $element->parent->title, - 'children' => $this->getChildren($element->children), - ]; - $el['progress'] = $this->getProgress($course, $element, $course_progress, $cw_user_progresses, $course_member_ids); + private function findElements(Instance $instance, User $user): iterable + { + $elements = $instance->getRoot()->findDescendants($user); + $elements[] = $instance->getRoot(); - array_push($data, $el); - } + return array_combine(array_column($elements, 'id'), $elements); + } - //update children progress - foreach ($data as &$element) { - if (count($element['children'])) { - foreach ($element['children'] as &$child) { - foreach ($data as $el) { - if ($el['id'] == $child['id']) { - $child['progress'] = $el['progress']; - } - } + private function computeChildrenOf(iterable $elements): iterable + { + $childrenOf = []; + foreach ($elements as $elementId => $element) { + if ($element['parent_id']) { + if (!isset($childrenOf[$element['parent_id']])) { + $childrenOf[$element['parent_id']] = []; } + $childrenOf[$element['parent_id']][] = $elementId; } } - return $data; + return $childrenOf; } - private function getChildren($children): array - { - $data = []; - foreach ($children as $child) { - $el = [ - 'id' => $child->id, - 'name' => $child->title, + private function computeSelfProgresses( + Instance $instance, + User $user, + iterable $elements, + bool $showProgressForAllParticipants + ): iterable { + $progress = []; + /** @var \Course $course */ + $course = $instance->getRange(); + $allBlocks = $instance->findAllBlocksGroupedByStructuralElementId(); + $courseMemberIds = $showProgressForAllParticipants + ? array_column($course->getMembersWithStatus('autor'), 'user_id') + : [$user->getId()]; + $userProgresses = UserProgress::findBySQL('user_id IN (?)', [$courseMemberIds]); + foreach ($elements as $elementId => $element) { + $selfProgress = $this->getSelfProgresses($allBlocks, $elementId, $userProgresses, $courseMemberIds); + $progress[$elementId] = [ + 'self' => $selfProgress['counter'] ? $selfProgress['progress'] / $selfProgress['counter'] : 1, ]; - array_push($data, $el); + } + + return $progress; + } + + private function getSelfProgresses( + array $allBlocks, + string $elementId, + array $userProgresses, + array $courseMemberIds + ): array { + $blks = $allBlocks[$elementId] ?: []; + + $data = [ + 'counter' => count($blks), + 'progress' => 0, + ]; + $usersCounter = count($courseMemberIds); + foreach ($blks as $blk) { + $progresses = array_filter($userProgresses, function ($progress) use ($blk, $courseMemberIds) { + return $progress->block_id === $blk->getId() && in_array($progress->user_id, $courseMemberIds); + }); + $usersProgress = count($progresses) ? array_sum(array_column($progresses, 'grade')) : 0; + + $data['progress'] += $usersProgress / $usersCounter; } return $data; } - private function getProgress(Course $course, StructuralElement $element, bool $course_progress = false, array $cw_user_progresses, array $course_member_ids): array + private function computeCumulativeProgresses(Instance $instance, iterable $elements, iterable $progress): iterable { - $descendants = $element->findDescendants(\User::findCurrent()); - $count = count($descendants); - $progress = 0; - $own_progress = 0; - - foreach ($descendants as $el) { - $block = $this->getBlocks($el->id, $course_progress, $cw_user_progresses, $course, $course_member_ids); - if ($block['counter'] > 0) { - $progress += $block['progress'] / $block['counter']; - } else { - $progress += 1; + $childrenOf = $this->computeChildrenOf($elements); + + // compute `cumulative` of each element + $visitor = function (&$progress, $element) use (&$childrenOf, &$elements, &$visitor) { + $elementId = $element->getId(); + $numberOfNodes = 0; + $cumulative = 0; + + // visit children first + if (isset($childrenOf[$elementId])) { + foreach ($childrenOf[$elementId] as $childId) { + $visitor($progress, $elements[$childId]); + $numberOfNodes += $progress[$childId]['numberOfNodes']; + $cumulative += $progress[$childId]['cumulative']; + } } - } - $own_blocks = $this->getBlocks($element->id, $course_progress, $cw_user_progresses, $course, $course_member_ids); + $progress[$elementId]['cumulative'] = $cumulative + $progress[$elementId]['self']; + $progress[$elementId]['numberOfNodes'] = $numberOfNodes + 1; - if ($own_blocks['counter'] > 0) { - $own_progress = $own_blocks['progress'] / $own_blocks['counter']; - } else { - $own_progress = 1; - } + return $progress; + }; - $count = count($descendants); - if ($count > 0) { - $progress = ($progress + $own_progress) / ($count + 1); - } else { - $progress = $own_progress; - } + $visitor($progress, $instance->getRoot()); - return ['total' => round($progress, 2) * 100, 'current' => round($own_progress, 2) * 100]; + return $progress; } - private function getBlocks(string $element_id, bool $course_progress = false, array $cw_user_progresses, Course $course, array $course_member_ids): array + private function prepareProgressData(iterable $elements, iterable $progress): iterable { - $containers = Courseware\Container::findBySQL('structural_element_id = ?', [intval($element_id)]); - $blocks = []; - $blocks['counter'] = 0; - $blocks['progress'] = 0; - $users_counter = count($course->getMembersWithStatus('autor')); - - foreach ($containers as $container) { - $counter = $container->countBlocks(); - - $blocks['counter'] += $counter; - if ($counter > 0) { - $blks = Courseware\Block::findBySQL('container_id = ?', [$container->id]); - foreach ($blks as $item) { - if ($course_progress) { - if ($users_counter > 0) { - $progresses = array_filter($cw_user_progresses, function($progress) use ($item) { - if ($progress->block_id === $item->id) { - return true; - } - }); - - $users_progress = 0; - foreach ($progresses as $prog) { - if (in_array($prog->user_id, $course_member_ids)) { - $users_progress += $prog->grade; - } - } - - $blocks['progress'] += $users_progress / $users_counter; - } - } else { - $uid = $GLOBALS['user']->id; - $progresses = array_filter($cw_user_progresses, function($progress) use ($item, $uid) { - if ($progress->block_id === $item->id && $progress->user_id === $uid) { - return true; - } - }); - $progress = reset($progresses); - if ($progress !== null) { - $blocks['progress'] += intval($progress->grade); - } - } - } - } + $data = []; + foreach ($elements as $elementId => $element) { + $elementProgress = $progress[$elementId]; + $cumulative = $elementProgress['cumulative'] / $elementProgress['numberOfNodes']; + + $data[$elementId] = [ + 'id' => (int) $elementId, + 'parent_id' => (int) $element['parent_id'], + 'name' => $element['title'], + 'progress' => [ + 'cumulative' => round($cumulative, 2) * 100, + 'self' => round($elementProgress['self'], 2) * 100, + ], + ]; } - return $blocks; + return $data; } private function getChapterCounter(array $chapters): array @@ -261,13 +254,13 @@ class Course_CoursewareController extends AuthenticatedController foreach ($chapters as $chapter) { if ($chapter['parent_id'] != null) { - if ($chapter['progress']['current'] == 0) { + if ($chapter['progress']['self'] == 0) { $ahead += 1; } - if ($chapter['progress']['current'] > 0 && $chapter['progress']['current'] < 100) { + if ($chapter['progress']['self'] > 0 && $chapter['progress']['self'] < 100) { $started += 1; } - if ($chapter['progress']['current'] == 100) { + if ($chapter['progress']['self'] == 100) { $finished += 1; } } |
