Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin: Add course/session report with links to tools - refs #2034 #6037

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions public/main/admin/statistics/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@
get_lang('Courses') => [
'report=courses' => get_lang('Courses'),
'report=tools' => get_lang('Tools access'),
'report=tool_usage' => get_lang('Tool Usage Report'),
'report=courselastvisit' => get_lang('Latest access'),
'report=coursebylanguage' => get_lang('Number of courses by language'),
],
Expand Down Expand Up @@ -708,6 +709,66 @@
$content .= '<canvas class="col-md-12" id="canvas" height="300px" style="margin-bottom: 20px"></canvas>';
$content .= Statistics::printToolStats();
break;
case 'tool_usage':
$courseTools = Statistics::getAvailableTools();

if (empty($courseTools)) {
$content .= '<div class="alert alert-info">'.get_lang('No tools available for this report').'</div>';
break;
}

$form = new FormValidator('tool_usage', 'get');
$form->addHeader(get_lang('Tool Usage Report'));
$form->addSelect(
'tool_ids',
get_lang('Select Tools'),
$courseTools,
['multiple' => true, 'required' => true]
);
$form->addButtonSearch(get_lang('Generate Report'));
$form->addHidden('report', 'tool_usage');

$content .= $form->returnForm();

if ($form->validate()) {
$values = $form->getSubmitValues();
$toolIds = $values['tool_ids'];
$reportData = Statistics::getToolUsageReportByTools($toolIds);

$table = new HTML_Table(['class' => 'table table-hover table-striped data_table stats_table']);
$headers = [
get_lang('Tool'),
get_lang('Session'),
get_lang('Course'),
get_lang('Items Count'),
get_lang('Last Updated'),
];
$row = 0;

foreach ($headers as $index => $header) {
$table->setHeaderContents($row, $index, $header);
}
$row++;

foreach ($reportData as $data) {
$linkHtml = $data['link'] !== '-'
? sprintf(
'<a href="%s" class="text-blue-500 underline hover:text-blue-700" target="_self">%s</a>',
$data['link'],
htmlspecialchars($data['tool_name'])
)
: htmlspecialchars($data['tool_name']);

$table->setCellContents($row, 0, $linkHtml);
$table->setCellContents($row, 1, htmlspecialchars($data['session_name']));
$table->setCellContents($row, 2, htmlspecialchars($data['course_name']));
$table->setCellContents($row, 3, (int) $data['resource_count']);
$table->setCellContents($row, 4, htmlspecialchars($data['last_updated']));
$row++;
}
$content .= $table->toHtml();
}
break;
case 'coursebylanguage':
$content .= '<canvas class="col-md-12" id="canvas" height="300px" style="margin-bottom: 20px"></canvas>';
$result = Statistics::printCourseByLanguageStats();
Expand Down
24 changes: 24 additions & 0 deletions public/main/inc/lib/statistics.lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
use Chamilo\CoreBundle\Entity\MessageRelUser;
use Chamilo\CoreBundle\Entity\ResourceLink;
use Chamilo\CoreBundle\Entity\UserRelUser;
use Chamilo\CoreBundle\Component\Utils\ActionIcon;

Expand Down Expand Up @@ -1665,4 +1666,27 @@ public static function groupByMonth(array $registrations): array

return $groupedData;
}

/**
* Retrieves the available tools using the repository.
*/
public static function getAvailableTools(): array
{
$em = Database::getManager();
$repo = $em->getRepository(ResourceLink::class);

return $repo->getAvailableTools();
}

/**
* Generates a report of tool usage based on the provided tool IDs.
*/
public static function getToolUsageReportByTools(array $toolIds): array
{
$em = Database::getManager();
$repo = $em->getRepository(ResourceLink::class);

return $repo->getToolUsageReportByTools($toolIds);
}

}
115 changes: 115 additions & 0 deletions src/CoreBundle/Repository/ResourceLinkRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@

class ResourceLinkRepository extends SortableRepository
{
private array $toolList = [
'course_description' => '/main/course_description/index.php',
'document' => '/resources/document/%resource_node_id%/',
'learnpath' => '/main/lp/lp_controller.php',
'link' => '/resources/links/%resource_node_id%/',
'quiz' => '/main/exercise/exercise.php',
'announcement' => '/main/announcements/announcements.php',
'glossary' => '/resources/glossary/%resource_node_id%/',
'attendance' => '/main/attendance/index.php',
'course_progress' => '/main/course_progress/index.php',
'agenda' => '/resources/ccalendarevent',
'forum' => '/main/forum/index.php',
'student_publication' => '/resources/assignment/%resource_node_id%',
'survey' => '/main/survey/survey_list.php',
'notebook' => '/main/notebook/index.php',
];

public function __construct(EntityManagerInterface $em)
{
parent::__construct($em, $em->getClassMetadata(ResourceLink::class));
Expand Down Expand Up @@ -50,4 +67,102 @@ public function removeByResourceInContext(
$this->remove($link);
}
}

/**
* Retrieves the list of available tools filtered by a predefined tool list.
*
* @return array The list of tools with their IDs and titles.
*/
public function getAvailableTools(): array
{
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder
->select('DISTINCT t.id, t.title')
->from('ChamiloCoreBundle:ResourceLink', 'rl')
->innerJoin('ChamiloCoreBundle:ResourceType', 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
->innerJoin('ChamiloCoreBundle:Tool', 't', 'WITH', 't.id = rt.tool')
->where('rl.course IS NOT NULL')
->andWhere('t.title IN (:toolList)')
->setParameter('toolList', array_keys($this->toolList));

$result = $queryBuilder->getQuery()->getArrayResult();

$tools = [];
foreach ($result as $row) {
$tools[$row['id']] = ucfirst(str_replace('_', ' ', $row['title']));
}

return $tools;
}

/**
* Retrieves a usage report of tools with dynamic links.
*
* @return array The tool usage data including counts, last update timestamps, and dynamic links.
*/
public function getToolUsageReportByTools(array $toolIds): array
{
$queryBuilder = $this->_em->createQueryBuilder();

$queryBuilder
->select(
'COUNT(rl.id) AS resource_count',
'IDENTITY(rl.course) AS course_id',
'IDENTITY(rl.session) AS session_id',
'IDENTITY(c.resourceNode) AS course_resource_node_id',
't.title AS tool_name',
'c.title AS course_name',
's.title AS session_name',
'MAX(rl.updatedAt) AS last_updated'
)
->from('ChamiloCoreBundle:ResourceLink', 'rl')
->innerJoin('ChamiloCoreBundle:ResourceType', 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
->innerJoin('ChamiloCoreBundle:Tool', 't', 'WITH', 't.id = rt.tool')
->innerJoin('ChamiloCoreBundle:Course', 'c', 'WITH', 'c.id = rl.course')
->leftJoin('ChamiloCoreBundle:Session', 's', 'WITH', 's.id = rl.session')
->where($queryBuilder->expr()->in('t.id', ':toolIds'))
->groupBy('rl.course, rl.session, t.title')
->orderBy('t.title', 'ASC')
->addOrderBy('c.title', 'ASC')
->addOrderBy('s.title', 'ASC')
->setParameter('toolIds', $toolIds);

$result = $queryBuilder->getQuery()->getArrayResult();

return array_map(function ($row) {
$toolName = $row['tool_name'];
$baseLink = $this->toolList[$toolName] ?? null;

if ($baseLink) {
$link = str_replace(
['%resource_node_id%'],
[$row['course_resource_node_id']],
$baseLink
);

$queryParams = [
'cid' => $row['course_id'],
];

if (!empty($row['session_id'])) {
$queryParams['sid'] = $row['session_id'];
}

$link .= '?' . http_build_query($queryParams);
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method getToolUsageReportByTools uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.

$link = '-';
}

return [
'tool_name' => $toolName,
'session_id' => $row['session_id'],
'session_name' => $row['session_name'] ?: '-',
'course_id' => $row['course_id'],
'course_name' => $row['course_name'],
'resource_count' => (int)$row['resource_count'],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cast statement must be followed by a single space

'last_updated' => $row['last_updated'] ?: '-',
'link' => $link,
];
}, $result);
}
}
Loading