MDL-83899 mod_scorm: Add course overview page

This commit is contained in:
Laurent David
2025-08-11 12:56:53 +02:00
parent 242b782fcb
commit cf97babf9d
5 changed files with 776 additions and 0 deletions
@@ -0,0 +1,184 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_scorm\courseformat;
use cm_info;
use core_calendar\output\humandate;
use core_courseformat\local\overview\overviewitem;
use core_courseformat\output\local\overview\overviewdialog;
use core\output\action_link;
use core\output\local\properties\text_align;
use core\output\local\properties\button;
use core\url;
use mod_data\dates;
use mod_scorm\manager;
/**
* SCORM activity overview integration.
*
* @package mod_scorm
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class overview extends \core_courseformat\activityoverviewbase {
/**
* @var manager the SCORM manager instance.
*/
protected manager $manager;
/**
* Constructor.
*
* @param cm_info $cm the course module instance.
* @param \core\output\renderer_helper $rendererhelper the renderer helper.
*/
public function __construct(
cm_info $cm,
/** @var \core\output\renderer_helper $rendererhelper the renderer helper */
protected readonly \core\output\renderer_helper $rendererhelper,
) {
parent::__construct($cm);
$this->manager = manager::create_from_coursemodule($cm);
}
#[\Override]
public function get_due_date_overview(): ?overviewitem {
global $USER;
$dates = dates::get_dates_for_module($this->cm, $USER->id);
$duedate = null;
foreach ($dates as $date) {
if ($date['dataid'] === 'timeclose') {
$duedate = $date['timestamp'];
break;
}
}
if (empty($duedate)) {
return new overviewitem(
name: get_string('duedate', 'assign'),
value: null,
content: '-',
);
}
$content = humandate::create_from_timestamp($duedate);
return new overviewitem(
name: get_string('duedate', 'assign'),
value: $duedate,
content: $content,
);
}
#[\Override]
public function get_actions_overview(): ?overviewitem {
if (!$this->manager->can_view_reports()) {
return null;
}
$viewresults = get_string('view');
$content = new action_link(
url: new url('/mod/scorm/report.php', ['id' => $this->cm->id]),
text: $viewresults,
attributes: ['class' => button::SECONDARY_OUTLINE->classes()],
);
return new overviewitem(
name: get_string('actions'),
value: '',
content: $content,
textalign: text_align::CENTER,
);
}
#[\Override]
public function get_extra_overview_items(): array {
return [
'attempted' => $this->get_extra_studentsattempted_overview(),
'totalattempts' => $this->get_extra_totalattempts_overview(),
];
}
/**
* Get the students who attempted.
*
* @return overviewitem|null The overview item.
*/
private function get_extra_studentsattempted_overview(): ?overviewitem {
if (!$this->manager->can_view_reports()) {
return null;
}
$attemptcount = $this->manager->count_users_who_attempted();
$participantscount = $this->manager->count_participants();
$params = [
'count' => $attemptcount,
'total' => $participantscount,
];
$content = get_string('count_of_total', 'core', $params);
return new overviewitem(
name: get_string('studentattempted', 'mod_scorm'),
value: $attemptcount,
content: $content,
textalign: text_align::END,
);
}
/**
* Get the "Total attempts" colum data.
*
* @return overviewitem|null The overview item.
*/
private function get_extra_totalattempts_overview(): ?overviewitem {
if (!$this->manager->can_view_reports()) {
return null;
}
$totalattempts = $this->manager->count_users_who_attempted();
$userswhocanattempt = $this->manager->count_participants();
$maxattempts = $this->manager->get_max_attempts();
if ($maxattempts === 0) {
$maxattemptstext = get_string('unlimited');
} else {
$maxattemptstext = (string) $maxattempts;
}
$content = new overviewdialog(
buttoncontent: $totalattempts,
title: get_string('totalattempts', 'mod_scorm'),
definition: ['buttonclasses' => button::SECONDARY_OUTLINE->classes() . ' dropdown-toggle'],
);
$gradingmethod = $this->manager->get_grading_method();
$content->add_item(
get_string('gradingmethod', 'grading'),
$gradingmethod ?? '-',
);
$content->add_item(get_string('allowedattemptsstudent', 'mod_scorm'), $maxattemptstext);
$averageattempts = 0;
if ($userswhocanattempt > 0) {
$averageattempts = (int) round($totalattempts / $userswhocanattempt);
}
$content->add_item(get_string('averageattemptperstudent', 'mod_scorm'), $averageattempts);
return new overviewitem(
name: get_string('totalattempts', 'mod_scorm'),
value: $totalattempts,
content: $content,
textalign: text_align::START,
);
}
}
+4
View File
@@ -37,6 +37,7 @@ $string['adminsettings'] = 'Admin settings';
$string['advanced'] = 'Parameters';
$string['aliasonly'] = 'When selecting an imsmanifest.xml file from a repository you must use an alias/shortcut for this file.';
$string['allowapidebug'] = 'Activate API debug and tracing (set the capture mask with apidebugmask)';
$string['allowedattemptsstudent'] = 'Allowed attempts per student';
$string['allowtypeexternal'] = 'Enable external package type';
$string['allowtypeexternalaicc'] = 'Enable direct AICC URL';
$string['allowtypeexternalaicc_desc'] = 'If enabled this allows a direct url to a simple AICC package';
@@ -64,6 +65,7 @@ $string['autocontinue'] = 'Auto-continue';
$string['autocontinue_help'] = 'If enabled, subsequent learning objects are launched automatically, otherwise the Continue button must be used.';
$string['autocontinuedesc'] = 'If enabled, subsequent learning objects are launched automatically, otherwise the Continue button must be used.';
$string['averageattempt'] = 'Average attempts';
$string['averageattemptperstudent'] = 'Average attempts per student';
$string['badmanifest'] = 'Some manifest errors: see errors log';
$string['badimsmanifestlocation'] = 'An imsmanifest.xml file was found but it was not in the root of your zip file, please re-package your SCORM';
$string['badarchive'] = 'You must provide a valid zip file';
@@ -413,6 +415,7 @@ $string['started'] = 'Started on';
$string['status'] = 'Status';
$string['statusbar'] = 'Show the status bar';
$string['student_response'] = 'Response';
$string['studentattempted'] = 'Student who attempted';
$string['subplugintype_scormreport'] = 'Report';
$string['subplugintype_scormreport_plural'] = 'Reports';
$string['suspended'] = 'Suspended';
@@ -423,6 +426,7 @@ $string['title'] = 'Title';
$string['toolbar'] = 'Show the toolbar';
$string['too_many_attributes'] = 'Tag {$a->tag} has too many attributes';
$string['too_many_children'] = 'Tag {$a->tag} has too many children';
$string['totalattempts'] = 'Total attempts';
$string['totaltime'] = 'Time';
$string['trackingloose'] = 'WARNING: The tracking data of this package will be lost!';
$string['type'] = 'Type';
@@ -0,0 +1,89 @@
@mod @mod_scorm
Feature: Testing overview integration in mod_scorm
In order to summarize the scorm activities
As a user
I need to be able to see the scorm overview
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Username | 1 |
| student2 | Username | 2 |
| student3 | Username | 3 |
| student4 | Username | 4 |
| student5 | Username | 5 |
| student6 | Username | 6 |
| student7 | Username | 7 |
| student8 | Username | 8 |
| teacher1 | Teacher | T |
| editingteacher1 | EditingTeacher | T |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| teacher1 | C1 | teacher |
| editingteacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | course | name | packagefilepath | forcenewattempt | idnumber | timeclose | grademethod |
| scorm | C1 | Scorm 1 | mod/scorm/tests/packages/singlescobasic.zip | 0 | scorm1 | 1 January 2040 | 3 |
| scorm | C1 | Scorm 2 | mod/scorm/tests/packages/singlescobasic.zip | 0 | scorm2 | | 3 |
| scorm | C2 | Scorm 3 | mod/scorm/tests/packages/singlescobasic.zip | 0 | scorm3 | | 3 |
And the following "mod_scorm > attempts" exist:
| scorm | user | attempt | element | value | scoidentifier |
| scorm1 | student1 | 1 | cmi.core.score.raw | 50 | item_1 |
| scorm1 | student1 | 1 | cmi.completion_status | completed | item_1 |
| scorm1 | student2 | 1 | cmi.core.score.raw | 100 | item_1 |
| scorm1 | student2 | 1 | cmi.completion_status | completed | item_1 |
Scenario: The scorm overview report should generate log events
Given I am on the "Course 1" "course > activities > scorm" page logged in as "editingteacher1"
When I am on the "Course 1" "course" page logged in as "editingteacher1"
And I navigate to "Reports" in current page administration
And I click on "Logs" "link"
And I click on "Get these logs" "button"
Then I should see "Course activities overview page viewed"
And I should see "viewed the instance list for the module 'scorm'"
@javascript
Scenario: Teachers can see relevant columns in the scorm overview
When I am on the "Course 1" "course > activities > scorm" page logged in as "teacher1"
Then I should see "Name" in the "scorm_overview_collapsible" "region"
And I should see "Due date" in the "scorm_overview_collapsible" "region"
And I should see "Student who attempted" in the "scorm_overview_collapsible" "region"
And I should see "Total attempts" in the "scorm_overview_collapsible" "region"
And I should see "Actions" in the "scorm_overview_collapsible" "region"
Then the following should exist in the "Table listing all SCORM package activities" table:
| Name | Due date | Student who attempted | Total attempts | Actions |
| Scorm 1 | Sunday, 1 January 2040, 12:00 AM | 2 of 5 | 2 | View |
| Scorm 2 | - | 0 of 5 | 0 | View |
@javascript
Scenario: Teachers can see relevant columns when there are no participants in the course
When I am on the "Course 2" "course > activities > scorm" page logged in as "admin"
Then I should see "Name" in the "scorm_overview_collapsible" "region"
And I should see "Student who attempted" in the "scorm_overview_collapsible" "region"
And I should see "Total attempts" in the "scorm_overview_collapsible" "region"
And I should see "Actions" in the "scorm_overview_collapsible" "region"
Then the following should exist in the "Table listing all SCORM package activities" table:
| Name | Student who attempted | Total attempts | Actions |
| Scorm 3 | 0 of 0 | 0 | View |
@javascript
Scenario Template: Students can see relevant columns in the scorm overview
When I am on the "Course 1" "course > activities > scorm" page logged in as "<student>"
Then I should see "Name" in the "scorm_overview_collapsible" "region"
And I should see "Due date" in the "scorm_overview_collapsible" "region"
And I should see "Grade" in the "scorm_overview_collapsible" "region"
Then the following should exist in the "Table listing all SCORM package activities" table:
| Name | Due date | Grade |
| Scorm 1 | 1 January 2040 | <grade> |
| Scorm 2 | - | - |
Examples:
| student | grade |
| student1 | 50.00 |
| student2 | 100.00 |
@@ -0,0 +1,441 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_scorm\courseformat;
use core_courseformat\local\overview\overviewfactory;
/**
* Tests for SCORM activity overview
*
* @covers \mod_scorm\courseformat\overview
* @package mod_scorm
* @category test
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class overview_test extends \advanced_testcase {
/**
* Test get_actions_overview.
*
* @covers ::get_actions_overview
*/
public function test_get_actions_overview(): void {
$this->resetAfterTest();
['users' => $users, 'course' => $course, 'instances' => $instances] = $this->setup_users_and_activity();
['withattempts' => $instancewa] = $instances;
$cm = get_fast_modinfo($course)->get_cm($instancewa->cmid);
// Students have no action column.
$this->setUser($users['s1']);
$this->assertNull(overviewfactory::create($cm)->get_actions_overview());
// Teachers have a 'View results' button.
$this->setUser($users['t1']);
$items = overviewfactory::create($cm)->get_actions_overview();
$this->assertNotNull($items);
$this->assertEquals(get_string('actions'), $items->get_name());
}
/**
* Test get_due_date_overview method.
*
* @param int|null $timeincrement
*
* @covers ::get_due_date_overview
* @dataProvider get_due_date_overview_data
*/
public function test_get_due_date_overview(?int $timeincrement = null): void {
$this->resetAfterTest();
$this->setAdminUser();
$scormtemplate = [];
$clock = $this->mock_clock_with_frozen();
if (!is_null($timeincrement)) {
$scormtemplate['timeclose'] = $clock->time() + $timeincrement;
}
['users' => $users, 'course' => $course, 'instances' => $instances] =
$this->setup_users_and_activity(instancedata: $scormtemplate);
['withattempts' => $instancewa] = $instances;
$cm = get_fast_modinfo($course)->get_cm($instancewa->cmid);
$this->setUser($users['s1']);
$overview = overviewfactory::create($cm);
$this->assertEquals(
is_null($timeincrement) ? null : $clock->time() + $timeincrement,
$overview->get_due_date_overview()->get_value(),
);
}
/**
* Data provider for test_get_due_date_overview.
*
* @return array
*/
public static function get_due_date_overview_data(): array {
return [
'tomorrow' => [
'timeincrement' => DAYSECS,
],
'yesterday' => [
'timeincrement' => -1 * DAYSECS,
],
'today' => [
'timeincrement' => 0,
],
'No date' => [
'timeincrement' => null,
],
];
}
/**
* Test get_extra_studentsattempted_overview.
*
* @param string $username
* @param int $groupmode
* @param array $expected
*
* @covers ::get_extra_studentsattempted_overview
* @dataProvider get_extra_overview_items_data
*/
public function test_get_extra_totalattempts_overview(string $username, int $groupmode, array $expected): void {
global $PAGE;
$this->resetAfterTest();
['users' => $users, 'course' => $course, 'instances' => $instances] = $this->setup_users_and_activity($groupmode);
foreach ($expected as $instancekey => $expectedvalues) {
$instance = $instances[$instancekey];
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$this->setUser($users[$username]);
$items = overviewfactory::create($cm)->get_extra_overview_items();
if (!isset($expectedvalues['totalattempts'])) {
$this->assertArrayNotHasKey('totalattempts', $items);
return;
}
$this->assertEquals(
$expectedvalues['totalattempts']['value'],
$items['totalattempts']->get_value(),
"Failed for instance: $instancekey"
);
$content = $items['totalattempts']->get_content()->export_for_template($PAGE->get_renderer('core'));
$contentitems = $content['items'] ?? [];
$this->assertCount(
count($expectedvalues['totalattempts']['items']),
$contentitems,
);
foreach ($expectedvalues['totalattempts']['items'] as $item) {
$currentitem = array_shift($contentitems);
$this->assertEquals(
(object) $item,
$currentitem,
"Failed for instance: $instancekey"
);
}
}
}
/**
* Test get_extra_studentsattempted_overview.
*
* @param string $username
* @param int $groupmode
* @param array $expected
*
* @covers ::get_extra_studentsattempted_overview
* @dataProvider get_extra_overview_items_data
*/
public function test_get_extra_studentsattempted_overview(string $username, int $groupmode, array $expected): void {
$this->resetAfterTest();
['users' => $users, 'course' => $course, 'instances' => $instances] = $this->setup_users_and_activity($groupmode);
foreach ($expected as $instancekey => $expectedvalues) {
$instance = $instances[$instancekey];
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$this->setUser($users[$username]);
$items = overviewfactory::create($cm)->get_extra_overview_items();
if (!isset($expectedvalues['attempted'])) {
$this->assertArrayNotHasKey('attempted', $items);
return;
}
$this->assertEquals(
$expectedvalues['attempted']['value'],
$items['attempted']->get_value(),
"Failed for instance: $instancekey"
);
$this->assertEquals(
$expectedvalues['attempted']['content'],
$items['attempted']->get_content(),
"Failed for instance: $instancekey"
);
}
}
/**
* Test get_extra_overview_items when there are no users in the course
*
* @return void
*/
public function test_get_extra_overview_no_users(): void {
global $PAGE;
$this->resetAfterTest();
['course' => $course, 'instances' => $instances] = $this->setup_users_and_activity(createusers: false);
['withattempts' => $instancewa] = $instances; // This has no user so no attempt too.
$cm = get_fast_modinfo($course)->get_cm($instancewa->cmid);
$this->setAdminUser();
$items = overviewfactory::create($cm)->get_extra_overview_items();
$this->assertArrayHasKey('attempted', $items);
$this->assertEquals(
0,
$items['attempted']->get_value(),
'Expected no attempts when there are no users in the course.'
);
$this->assertEquals(
'<strong>0</strong> of 0',
$items['attempted']->get_content(),
'Expected no attempts when there are no users in the course.'
);
$this->assertArrayHasKey('totalattempts', $items);
$this->assertEquals(
0,
$items['totalattempts']->get_value(),
'Expected no total attempts when there are no users in the course.'
);
$content = $items['totalattempts']->get_content()->export_for_template($PAGE->get_renderer('core'));
$this->assertCount(
3,
$content['items'],
'Expected items even if the content is empty.'
);
$items = $content['items'];
$this->assertEquals(
(object) ['label' => 'Grading method', 'value' => 'Highest attempt'],
array_shift($items),
'Expected grading method item.'
);
$this->assertEquals(
(object) ['label' => 'Allowed attempts per student', 'value' => 'Unlimited'],
array_shift($items),
'Expected allowed attempts item.'
);
$this->assertEquals(
(object) ['label' => 'Average attempts per student', 'value' => '0'],
array_shift($items),
'Expected average attempts item.'
);
}
/**
* Data provider for test_get_extra_studentsattempted_overview and test_get_extra_totalattempts_overview
*
* @return array
*/
public static function get_extra_overview_items_data(): array {
// Here we intentionally just test the case where course mode is set to NOGROUPS as groups are is not
// yet supported by the overview page for SCORM module. This will be followed up in a future issue (MDL-85852).
return [
'teacher 1 - no groups' => [
'username' => 't1',
'groupmode' => NOGROUPS,
'expected' => [
'withattempts' => [
'attempted' => [
'value' => 2,
'content' => '<strong>2</strong> of 4',
],
'totalattempts' => [
'value' => 2,
'items' => [
[
'label' => 'Grading method',
'value' => 'Highest attempt',
],
[
'label' => 'Allowed attempts per student',
'value' => 'Unlimited',
],
[
'label' => 'Average attempts per student',
'value' => '1',
],
],
],
],
'withoutattempts' => [
'attempted' => [
'value' => 0,
'content' => '<strong>0</strong> of 4',
],
'totalattempts' => [
'value' => 0,
'items' => [
[
'label' => 'Grading method',
'value' => 'Highest attempt',
],
[
'label' => 'Allowed attempts per student',
'value' => 'Unlimited',
],
[
'label' => 'Average attempts per student',
'value' => '0',
],
],
],
],
],
],
'teacher 2 - no groups' => [
'username' => 't2',
'groupmode' => NOGROUPS,
'expected' => [
'withattempts' => [
'attempted' => [
'value' => 2,
'content' => '<strong>2</strong> of 4',
],
'totalattempts' => [
'value' => 2,
'items' => [
[
'label' => 'Grading method',
'value' => 'Highest attempt',
],
[
'label' => 'Allowed attempts per student',
'value' => 'Unlimited',
],
[
'label' => 'Average attempts per student',
'value' => '1',
],
],
],
],
'withoutattempts' => [
'attempted' => [
'value' => 0,
'content' => '<strong>0</strong> of 4',
],
'totalattempts' => [
'value' => 0,
'items' => [
[
'label' => 'Grading method',
'value' => 'Highest attempt',
],
[
'label' => 'Allowed attempts per student',
'value' => 'Unlimited',
],
[
'label' => 'Average attempts per student',
'value' => '0',
],
],
],
],
],
],
];
}
/**
* Setup users and activity for testing answers retrieval.
*
* @param int $groupmode the group mode to use for the course.
* @param bool $createattempt whether to create an attempt for the student.
* @param array|null $instancedata additional data for the instance.
* @param array|null $grades the grade to set for the student.
* @param bool $createusers whether to enrol users in the course.
* @return array indexed array with 'users', 'course' and 'instance'.
*/
private function setup_users_and_activity(
int $groupmode = NOGROUPS,
bool $createattempt = true,
?array $instancedata = null,
?array $grades = null,
bool $createusers = true,
): array {
global $CFG;
require_once($CFG->dirroot . '/mod/scorm/locallib.php');
$users = [];
$generator = $this->getDataGenerator();
$courseparams = [];
if ($groupmode !== NOGROUPS) {
// Set the group mode for the course.
$courseparams['groupmode'] = $groupmode;
$courseparams['groupmodeforce'] = 1; // Force the group mode.
}
$course = $generator->create_course($courseparams);
$groups = [];
if ($createusers) {
$data = [
's1' => ['role' => 'student', 'groups' => ['g1']],
's2' => ['role' => 'student', 'groups' => ['g2']],
't1' => ['role' => 'teacher', 'groups' => ['g1']],
't2' => ['role' => 'teacher', 'groups' => []],
];
// Enrol users in the course.
foreach ($data as $username => $userinfo) {
['role' => $role, 'groups' => $groups] = $userinfo;
$users[$username] = $generator->create_and_enrol($course, $role, ['username' => $username]);
foreach ($groups as $group) {
if (!isset($groups[$group])) {
// Create the group if it does not exist.
$groups[$group] = $generator->create_group(['courseid' => $course->id, 'name' => $group]);
}
// Add the user to the group.
groups_add_member($groups[$group], $users[$username]->id);
}
}
}
$this->setAdminUser();
$instancedata = $instancedata ?? [];
$instancedata = array_merge($instancedata, [
'course' => $course->id,
'grademethod' => GRADEHIGHEST, // Use highest grade for grading.
'whatgrade' => HIGHESTATTEMPT,
]);
$instances = [];
$instances['withattempts'] = $generator->create_module('scorm', $instancedata);
$instances['withoutattempts'] = $generator->create_module('scorm', $instancedata); // Create a second instance with no
// attempt for testing purposes.
if ($createattempt && $createusers) {
$scormgenerator = $this->getDataGenerator()->get_plugin_generator('mod_scorm');
// Create attempts for the students.
// Two attempts for the first student, one for the second.
foreach ($data as $username => $userinfo) {
$record = [
'userid' => $users[$username]->id,
'scormid' => $instances['withattempts']->id,
];
if (isset($grades[$username])) {
$record['element'] = 'cmi.core.score.raw';
$record['value'] = $grades[$username];
}
// Create an attempt for each student.
if ($userinfo['role'] === 'student') {
$scormgenerator->create_attempt($record);
}
}
}
return [
'users' => $users,
'course' => $course,
'instances' => $instances,
];
}
}
@@ -0,0 +1,58 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Behat data generator for mod_scorm.
*
* @package mod_scorm
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_scorm_generator extends behat_generator_base {
/**
* Get a list of the entities that Behat can create using the generator step.
*
* @return array
*/
protected function get_creatable_entities(): array {
return [
'grades' => [
'singular' => 'grades',
'datagenerator' => 'grade',
'required' => ['scorm', 'user'],
'switchids' => ['scorm' => 'scormid', 'user' => 'userid'],
],
'attempts' => [
'singular' => 'attempt',
'datagenerator' => 'attempt',
'required' => ['scorm', 'user'],
'switchids' => ['scorm' => 'scormid', 'user' => 'userid'],
],
];
}
/**
* Get the scorm cmid using an activity name or idnumber.
*
* @param string $identifier activity name or idnumber
* @return int The scorm instance id of the scorm activity.
*/
protected function get_scorm_id(string $identifier): int {
$cm = $this->get_cm_by_activity_name('scorm', $identifier);
$manager = \mod_scorm\manager::create_from_coursemodule($cm);
return $manager->get_instance()->id;
}
}