Skip to content

Commit b0bc531

Browse files
Admin: Add course/session report with links to tools - refs #2034
Author: @christianbeeznest
1 parent b66808c commit b0bc531

File tree

3 files changed

+197
-0
lines changed

3 files changed

+197
-0
lines changed

Diff for: public/main/admin/statistics/index.php

+61
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@
334334
get_lang('Courses') => [
335335
'report=courses' => get_lang('Courses'),
336336
'report=tools' => get_lang('Tools access'),
337+
'report=tool_usage' => get_lang('Tool-based resource count'),
337338
'report=courselastvisit' => get_lang('Latest access'),
338339
'report=coursebylanguage' => get_lang('Number of courses by language'),
339340
],
@@ -709,6 +710,66 @@
709710
$content .= '<canvas class="col-md-12" id="canvas" height="300px" style="margin-bottom: 20px"></canvas>';
710711
$content .= Statistics::printToolStats();
711712
break;
713+
case 'tool_usage':
714+
$courseTools = Statistics::getAvailableTools();
715+
716+
if (empty($courseTools)) {
717+
$content .= '<div class="alert alert-info">'.get_lang('No tools available for this report').'</div>';
718+
break;
719+
}
720+
721+
$form = new FormValidator('tool_usage', 'get');
722+
$form->addHeader(get_lang('Tool-based resource count'));
723+
$form->addSelect(
724+
'tool_ids',
725+
get_lang('Select Tools'),
726+
$courseTools,
727+
['multiple' => true, 'required' => true]
728+
);
729+
$form->addButtonSearch(get_lang('Generate report'));
730+
$form->addHidden('report', 'tool_usage');
731+
732+
$content .= $form->returnForm();
733+
734+
if ($form->validate()) {
735+
$values = $form->getSubmitValues();
736+
$toolIds = $values['tool_ids'];
737+
$reportData = Statistics::getToolUsageReportByTools($toolIds);
738+
739+
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table stats_table']);
740+
$headers = [
741+
get_lang('Tool'),
742+
get_lang('Session'),
743+
get_lang('Course'),
744+
get_lang('Resource count'),
745+
get_lang('Last updated'),
746+
];
747+
$row = 0;
748+
749+
foreach ($headers as $index => $header) {
750+
$table->setHeaderContents($row, $index, $header);
751+
}
752+
$row++;
753+
754+
foreach ($reportData as $data) {
755+
$linkHtml = $data['link'] !== '-'
756+
? sprintf(
757+
'<a href="%s" class="text-blue-500 underline hover:text-blue-700" target="_self">%s</a>',
758+
$data['link'],
759+
htmlspecialchars($data['tool_name'])
760+
)
761+
: htmlspecialchars($data['tool_name']);
762+
763+
$table->setCellContents($row, 0, $linkHtml);
764+
$table->setCellContents($row, 1, htmlspecialchars($data['session_name']));
765+
$table->setCellContents($row, 2, htmlspecialchars($data['course_name']));
766+
$table->setCellContents($row, 3, (int) $data['resource_count']);
767+
$table->setCellContents($row, 4, htmlspecialchars($data['last_updated']));
768+
$row++;
769+
}
770+
$content .= $table->toHtml();
771+
}
772+
break;
712773
case 'coursebylanguage':
713774
$content .= '<canvas class="col-md-12" id="canvas" height="300px" style="margin-bottom: 20px"></canvas>';
714775
$result = Statistics::printCourseByLanguageStats();

Diff for: public/main/inc/lib/statistics.lib.php

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
55
use Chamilo\CoreBundle\Entity\MessageRelUser;
6+
use Chamilo\CoreBundle\Entity\ResourceLink;
67
use Chamilo\CoreBundle\Entity\UserRelUser;
78
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
89
use Chamilo\CoreBundle\Framework\Container;
@@ -1784,6 +1785,28 @@ public static function groupByMonth(array $registrations): array
17841785
return $groupedData;
17851786
}
17861787

1788+
/**
1789+
* Retrieves the available tools using the repository.
1790+
*/
1791+
public static function getAvailableTools(): array
1792+
{
1793+
$em = Database::getManager();
1794+
$repo = $em->getRepository(ResourceLink::class);
1795+
1796+
return $repo->getAvailableTools();
1797+
}
1798+
1799+
/**
1800+
* Generates a report of tool usage based on the provided tool IDs.
1801+
*/
1802+
public static function getToolUsageReportByTools(array $toolIds): array
1803+
{
1804+
$em = Database::getManager();
1805+
$repo = $em->getRepository(ResourceLink::class);
1806+
1807+
return $repo->getToolUsageReportByTools($toolIds);
1808+
}
1809+
17871810
/**
17881811
* Return de number of certificates generated.
17891812
* This function is resource intensive.

Diff for: src/CoreBundle/Repository/ResourceLinkRepository.php

+113
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@
2121
*/
2222
class ResourceLinkRepository extends SortableRepository
2323
{
24+
private array $toolList = [
25+
'course_description' => '/main/course_description/index.php',
26+
'document' => '/resources/document/%resource_node_id%/',
27+
'learnpath' => '/main/lp/lp_controller.php',
28+
'link' => '/resources/links/%resource_node_id%/',
29+
'quiz' => '/main/exercise/exercise.php',
30+
'announcement' => '/main/announcements/announcements.php',
31+
'glossary' => '/resources/glossary/%resource_node_id%/',
32+
'attendance' => '/main/attendance/index.php',
33+
'course_progress' => '/main/course_progress/index.php',
34+
'agenda' => '/resources/ccalendarevent',
35+
'forum' => '/main/forum/index.php',
36+
'student_publication' => '/resources/assignment/%resource_node_id%',
37+
'survey' => '/main/survey/survey_list.php',
38+
'notebook' => '/main/notebook/index.php',
39+
];
40+
2441
public function __construct(EntityManagerInterface $em)
2542
{
2643
parent::__construct($em, $em->getClassMetadata(ResourceLink::class));
@@ -53,4 +70,100 @@ public function removeByResourceInContext(
5370
$this->remove($link);
5471
}
5572
}
73+
74+
/**
75+
* Retrieves the list of available tools filtered by a predefined tool list.
76+
*
77+
* @return array The list of tools with their IDs and titles.
78+
*/
79+
public function getAvailableTools(): array
80+
{
81+
$queryBuilder = $this->_em->createQueryBuilder();
82+
$queryBuilder
83+
->select('DISTINCT t.id, t.title')
84+
->from('ChamiloCoreBundle:ResourceLink', 'rl')
85+
->innerJoin('ChamiloCoreBundle:ResourceType', 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
86+
->innerJoin('ChamiloCoreBundle:Tool', 't', 'WITH', 't.id = rt.tool')
87+
->where('rl.course IS NOT NULL')
88+
->andWhere('t.title IN (:toolList)')
89+
->setParameter('toolList', array_keys($this->toolList));
90+
91+
$result = $queryBuilder->getQuery()->getArrayResult();
92+
93+
$tools = [];
94+
foreach ($result as $row) {
95+
$tools[$row['id']] = ucfirst(str_replace('_', ' ', $row['title']));
96+
}
97+
98+
return $tools;
99+
}
100+
101+
/**
102+
* Retrieves a usage report of tools with dynamic links.
103+
*
104+
* @return array The tool usage data including counts, last update timestamps, and dynamic links.
105+
*/
106+
public function getToolUsageReportByTools(array $toolIds): array
107+
{
108+
$queryBuilder = $this->_em->createQueryBuilder();
109+
110+
$queryBuilder
111+
->select(
112+
'COUNT(rl.id) AS resource_count',
113+
'IDENTITY(rl.course) AS course_id',
114+
'IDENTITY(rl.session) AS session_id',
115+
'IDENTITY(c.resourceNode) AS course_resource_node_id',
116+
't.title AS tool_name',
117+
'c.title AS course_name',
118+
's.title AS session_name',
119+
'MAX(rl.updatedAt) AS last_updated'
120+
)
121+
->from('ChamiloCoreBundle:ResourceLink', 'rl')
122+
->innerJoin('ChamiloCoreBundle:ResourceType', 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
123+
->innerJoin('ChamiloCoreBundle:Tool', 't', 'WITH', 't.id = rt.tool')
124+
->innerJoin('ChamiloCoreBundle:Course', 'c', 'WITH', 'c.id = rl.course')
125+
->leftJoin('ChamiloCoreBundle:Session', 's', 'WITH', 's.id = rl.session')
126+
->where($queryBuilder->expr()->in('t.id', ':toolIds'))
127+
->groupBy('rl.course, rl.session, t.title')
128+
->orderBy('t.title', 'ASC')
129+
->addOrderBy('c.title', 'ASC')
130+
->addOrderBy('s.title', 'ASC')
131+
->setParameter('toolIds', $toolIds);
132+
133+
$result = $queryBuilder->getQuery()->getArrayResult();
134+
135+
return array_map(function ($row) {
136+
$toolName = $row['tool_name'];
137+
$baseLink = $this->toolList[$toolName] ?? null;
138+
$link = '-';
139+
if ($baseLink) {
140+
$link = str_replace(
141+
['%resource_node_id%'],
142+
[$row['course_resource_node_id']],
143+
$baseLink
144+
);
145+
146+
$queryParams = [
147+
'cid' => $row['course_id'],
148+
];
149+
150+
if (!empty($row['session_id'])) {
151+
$queryParams['sid'] = $row['session_id'];
152+
}
153+
154+
$link .= '?' . http_build_query($queryParams);
155+
}
156+
157+
return [
158+
'tool_name' => $toolName,
159+
'session_id' => $row['session_id'],
160+
'session_name' => $row['session_name'] ?: '-',
161+
'course_id' => $row['course_id'],
162+
'course_name' => $row['course_name'],
163+
'resource_count' => (int) $row['resource_count'],
164+
'last_updated' => $row['last_updated'] ?: '-',
165+
'link' => $link,
166+
];
167+
}, $result);
168+
}
56169
}

0 commit comments

Comments
 (0)