Skip to content
Snippets Groups Projects
Commit b6389b54 authored by Marcus Eibrink-Lunzenauer's avatar Marcus Eibrink-Lunzenauer
Browse files

Courseware-Fortschrittseite beschleunigen (SORMless edition)

parent 27d90b64
No related branches found
No related tags found
No related merge requests found
...@@ -131,7 +131,7 @@ class Course_CoursewareController extends AuthenticatedController ...@@ -131,7 +131,7 @@ class Course_CoursewareController extends AuthenticatedController
return array_combine(array_column($elements, 'id'), $elements); return array_combine(array_column($elements, 'id'), $elements);
} }
private function computeChildrenOf(iterable $elements): iterable private function computeChildrenOf(iterable &$elements): iterable
{ {
$childrenOf = []; $childrenOf = [];
foreach ($elements as $elementId => $element) { foreach ($elements as $elementId => $element) {
...@@ -149,19 +149,28 @@ class Course_CoursewareController extends AuthenticatedController ...@@ -149,19 +149,28 @@ class Course_CoursewareController extends AuthenticatedController
private function computeSelfProgresses( private function computeSelfProgresses(
Instance $instance, Instance $instance,
User $user, User $user,
iterable $elements, iterable &$elements,
bool $showProgressForAllParticipants bool $showProgressForAllParticipants
): iterable { ): iterable {
$progress = []; $progress = [];
/** @var \Course $course */ /** @var \Course $course */
$course = $instance->getRange(); $course = $instance->getRange();
$allBlocks = $instance->findAllBlocksGroupedByStructuralElementId(); $allBlockIds = $instance->findAllBlocksGroupedByStructuralElementId(function ($row) {
return $row['id'];
});
$courseMemberIds = $showProgressForAllParticipants $courseMemberIds = $showProgressForAllParticipants
? array_column($course->getMembersWithStatus('autor'), 'user_id') ? array_column($course->getMembersWithStatus('autor'), 'user_id')
: [$user->getId()]; : [$user->getId()];
$userProgresses = UserProgress::findBySQL('user_id IN (?)', [$courseMemberIds]);
$sql =
'SELECT block_id, COUNT(grade) as count, SUM(grade) as grade ' .
'FROM cw_user_progresses ' .
'WHERE block_id IN (?) AND user_id IN (?) ' .
'GROUP BY block_id';
$userProgresses = \DBManager::get()->fetchGrouped($sql, [$allBlockIds, $courseMemberIds]);
foreach ($elements as $elementId => $element) { foreach ($elements as $elementId => $element) {
$selfProgress = $this->getSelfProgresses($allBlocks, $elementId, $userProgresses, $courseMemberIds); $selfProgress = $this->getSelfProgresses($allBlockIds, $elementId, $userProgresses, $courseMemberIds);
$progress[$elementId] = [ $progress[$elementId] = [
'self' => $selfProgress['counter'] ? $selfProgress['progress'] / $selfProgress['counter'] : 1, 'self' => $selfProgress['counter'] ? $selfProgress['progress'] / $selfProgress['counter'] : 1,
]; ];
...@@ -171,31 +180,35 @@ class Course_CoursewareController extends AuthenticatedController ...@@ -171,31 +180,35 @@ class Course_CoursewareController extends AuthenticatedController
} }
private function getSelfProgresses( private function getSelfProgresses(
array $allBlocks, array &$allBlockIds,
string $elementId, string $elementId,
array $userProgresses, array &$userProgresses,
array $courseMemberIds array &$courseMemberIds
): array { ): array {
$blks = $allBlocks[$elementId] ?: []; $blks = $allBlockIds[$elementId] ?: [];
if (!count($blks)) {
return [
'counter' => 0,
'progress' => 1,
];
}
$data = [ $data = [
'counter' => count($blks), 'counter' => count($blks),
'progress' => 0, 'progress' => 0,
]; ];
$usersCounter = count($courseMemberIds); $usersCounter = count($courseMemberIds);
foreach ($blks as $blk) { foreach ($blks as $blk) {
$progresses = array_filter($userProgresses, function ($progress) use ($blk, $courseMemberIds) { $progresses = $userProgresses[$blk];
return $progress->block_id === $blk->getId() && in_array($progress->user_id, $courseMemberIds); $usersProgress = $progresses['count'] ? (float) $progresses['sum'] : 0;
});
$usersProgress = count($progresses) ? array_sum(array_column($progresses, 'grade')) : 0;
$data['progress'] += $usersProgress / $usersCounter; $data['progress'] += $usersProgress / $usersCounter;
} }
return $data; return $data;
} }
private function computeCumulativeProgresses(Instance $instance, iterable $elements, iterable $progress): iterable private function computeCumulativeProgresses(Instance $instance, iterable &$elements, iterable &$progress): iterable
{ {
$childrenOf = $this->computeChildrenOf($elements); $childrenOf = $this->computeChildrenOf($elements);
...@@ -225,7 +238,7 @@ class Course_CoursewareController extends AuthenticatedController ...@@ -225,7 +238,7 @@ class Course_CoursewareController extends AuthenticatedController
return $progress; return $progress;
} }
private function prepareProgressData(iterable $elements, iterable $progress): iterable private function prepareProgressData(iterable &$elements, iterable &$progress): iterable
{ {
$data = []; $data = [];
foreach ($elements as $elementId => $element) { foreach ($elements as $elementId => $element) {
...@@ -246,7 +259,7 @@ class Course_CoursewareController extends AuthenticatedController ...@@ -246,7 +259,7 @@ class Course_CoursewareController extends AuthenticatedController
return $data; return $data;
} }
private function getChapterCounter(array $chapters): array private function getChapterCounter(array &$chapters): array
{ {
$finished = 0; $finished = 0;
$started = 0; $started = 0;
......
...@@ -37,12 +37,19 @@ class Instance ...@@ -37,12 +37,19 @@ class Instance
$range->getConfiguration()->delete('COURSEWARE_SEQUENTIAL_PROGRESSION'); $range->getConfiguration()->delete('COURSEWARE_SEQUENTIAL_PROGRESSION');
$range->getConfiguration()->delete('COURSEWARE_EDITING_PERMISSION'); $range->getConfiguration()->delete('COURSEWARE_EDITING_PERMISSION');
$last_element_configs = \ConfigValue::findBySQL('field = ? AND value LIKE ?', ['COURSEWARE_LAST_ELEMENT', '%'.$range->getRangeId().'%']); $last_element_configs = \ConfigValue::findBySQL('field = ? AND value LIKE ?', [
'COURSEWARE_LAST_ELEMENT',
'%' . $range->getRangeId() . '%',
]);
foreach ($last_element_configs as $config) { foreach ($last_element_configs as $config) {
$arr = json_decode($config->value, true); $arr = json_decode($config->value, true);
$arr = array_filter($arr, function ($key) use ($range) { $arr = array_filter(
return $key !== $range->id; $arr,
}, ARRAY_FILTER_USE_KEY); function ($key) use ($range) {
return $key !== $range->id;
},
ARRAY_FILTER_USE_KEY
);
\UserConfig::get($config->range_id)->unsetValue('COURSEWARE_LAST_ELEMENT'); \UserConfig::get($config->range_id)->unsetValue('COURSEWARE_LAST_ELEMENT');
\UserConfig::get($config->range_id)->store('COURSEWARE_LAST_ELEMENT', $arr); \UserConfig::get($config->range_id)->store('COURSEWARE_LAST_ELEMENT', $arr);
} }
...@@ -270,8 +277,23 @@ class Instance ...@@ -270,8 +277,23 @@ class Instance
return $data; return $data;
} }
public function findAllBlocksGroupedByStructuralElementId(): iterable /**
* Find all blocks of this instance and group them by their structural element's ID.
* You may specify your own `$formatter` instead of the default one which stores the blocks as instances of \Courseware\Block.
*
* @param ?callable(array $row): mixed $formatter Provide your own callable if you need something else instead of
* full-blown instances of \Courseware\Block.
* @return iterable all the (optionally formatted) blocks grouped by the IDs of the structural element containing
* that block.
*/
public function findAllBlocksGroupedByStructuralElementId(callable $formatter = null): iterable
{ {
if (!$formatter) {
$formatter = function ($row) {
return \Courseware\Block::build($row, false);
};
}
$sql = 'SELECT se.id AS structural_element_id, b.* $sql = 'SELECT se.id AS structural_element_id, b.*
FROM cw_structural_elements se FROM cw_structural_elements se
JOIN cw_containers c ON se.id = c.structural_element_id JOIN cw_containers c ON se.id = c.structural_element_id
...@@ -286,11 +308,10 @@ class Instance ...@@ -286,11 +308,10 @@ class Instance
$structuralElementId = $row['structural_element_id']; $structuralElementId = $row['structural_element_id'];
unset($row['structural_element_id']); unset($row['structural_element_id']);
$block = \Courseware\Block::build($row, false);
if (!isset($data[$structuralElementId])) { if (!isset($data[$structuralElementId])) {
$data[$structuralElementId] = []; $data[$structuralElementId] = [];
} }
$data[$structuralElementId][] = $block; $data[$structuralElementId][] = $formatter($row);
} }
return $data; return $data;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment