diff --git a/classes/certificate.php b/classes/certificate.php
index f1a5c8d8..b770a370 100644
--- a/classes/certificate.php
+++ b/classes/certificate.php
@@ -110,7 +110,7 @@ public static function get_issues_for_template($templateid, $limitfrom, $limitnu
$userfields = self::get_extra_user_fields($context);
$sql = "SELECT ci.id as issueid, ci.code, ci.emailed, ci.timecreated, ci.userid, ci.templateid, ci.expires,
- t.name, ci.data, {$userfields}
+ COALESCE(ci.name, t.name) AS name, ci.data, {$userfields}
FROM {tool_certificate_templates} t
JOIN {tool_certificate_issues} ci
ON (ci.templateid = t.id)
@@ -245,7 +245,7 @@ public static function get_issues_for_course(int $templateid, int $courseid, str
$userfields = self::get_extra_user_fields($context);
$sql = "SELECT ci.id as issueid, ci.code, ci.emailed, ci.timecreated, ci.userid, ci.templateid, ci.expires,
- t.name, ci.courseid, ci.archived, $userfields,
+ COALESCE(ci.name, t.name) AS name, ci.courseid, ci.archived, $userfields,
CASE WHEN ci.expires > 0 AND ci.expires < :now THEN 0
ELSE 1
END AS status
@@ -317,7 +317,7 @@ public static function get_issues_for_user($userid, $limitfrom, $limitnum, $sort
}
$sql = "SELECT ci.id, ci.expires, ci.code, ci.timecreated, ci.userid, ci.courseid,
- t.id as templateid, t.contextid, t.name
+ t.id as templateid, t.contextid, COALESCE(ci.name, t.name) AS name
FROM {tool_certificate_templates} t
INNER JOIN {tool_certificate_issues} ci
ON t.id = ci.templateid
@@ -388,7 +388,8 @@ public static function verify($code) {
$sql = "SELECT ci.id, ci.templateid, ci.code, ci.emailed, ci.timecreated,
ci.expires, ci.data, ci.component, ci.courseid,
ci.userid, ci.archived,
- t.name as certificatename,
+ t.name AS certificatename,
+ ci.name,
t.contextid
FROM {tool_certificate_templates} t
JOIN {tool_certificate_issues} ci
diff --git a/classes/output/verify_certificate_result.php b/classes/output/verify_certificate_result.php
index 72d80132..ded5adeb 100644
--- a/classes/output/verify_certificate_result.php
+++ b/classes/output/verify_certificate_result.php
@@ -90,7 +90,7 @@ public function __construct($issue) {
$this->viewurl = template::view_url($issue->code);
$this->userprofileurl = new \moodle_url('/user/view.php', ['id' => $issue->userid]);
$this->userfullname = @json_decode($issue->data, true)['userfullname'];
- $this->certificatename = $issue->certificatename;
+ $this->certificatename = $issue->name ?? $issue->certificatename;
$strftimedatetime = get_string("strftimedatetime", "langconfig");
$this->timecreated = userdate($issue->timecreated, $strftimedatetime);
$this->expires = $issue->expires > 0
diff --git a/classes/reportbuilder/local/entities/issue.php b/classes/reportbuilder/local/entities/issue.php
index f2f9796e..595e75c3 100644
--- a/classes/reportbuilder/local/entities/issue.php
+++ b/classes/reportbuilder/local/entities/issue.php
@@ -118,6 +118,17 @@ protected function get_all_columns(): array {
->add_field("{$certificateissuealias}.code")
->add_callback([formatter::class, 'code_with_link']);
+ // Column certificate issue timecreated.
+ $columns[] = (new column(
+ 'name',
+ new lang_string('issuename', 'tool_certificate'),
+ $this->get_entity_name()
+ ))
+ ->add_joins($this->get_joins())
+ ->set_type(column::TYPE_TEXT)
+ ->set_is_sortable(true)
+ ->add_field("{$certificateissuealias}.name");
+
// Column certificate issue timecreated.
$columns[] = (new column(
'timecreated',
diff --git a/classes/template.php b/classes/template.php
index 856165b2..97eb6b5f 100644
--- a/classes/template.php
+++ b/classes/template.php
@@ -264,13 +264,13 @@ public function generate_pdf($preview = false, $issue = null, $return = false) {
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
- $pdf->SetTitle($this->get_formatted_name());
+ $pdf->SetTitle($this->get_formatted_name($issue));
$pdf->setViewerPreferences([
'DisplayDocTitle' => true,
]);
$pdf->SetAutoPageBreak(true, 0);
// Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
- $filename = rtrim($this->get_formatted_name(), '.');
+ $filename = rtrim($this->get_formatted_name($issue), '.');
$filename = clean_filename($filename . '.pdf');
// Loop through the pages and display their content.
foreach ($pages as $page) {
@@ -446,9 +446,13 @@ public function get_shared() {
/**
* Returns the formatted name of the template.
*
+ * @param \stdClass $issue The issued certificate we want to view
* @return string the name of the template
*/
- public function get_formatted_name() {
+ public function get_formatted_name(\stdClass $issue = null) {
+ if ($issue && $issue->name) {
+ return format_string($issue->name, true, ['escape' => false, 'context' => $this->get_context()]);
+ }
return $this->persistent->get_formatted_name();
}
@@ -688,11 +692,12 @@ public static function find_by_name($name) {
* @param array $data Additional data that will json_encode'd and stored with the issue.
* @param string $component The component the certificate was issued by.
* @param int|null $courseid
+ * @param string $name Override the name for a certificate to display in the user's list
* @param \core\lock\lock|null $lock optional lock to release after a record was inserted into the DB
* @return int The ID of the issue
*/
public function issue_certificate($userid, $expires = null, array $data = [], $component = 'tool_certificate',
- $courseid = null, ?\core\lock\lock $lock = null) {
+ $courseid = null, $name = null, ?\core\lock\lock $lock = null) {
global $DB;
component_class_callback(\tool_tenant\config::class, 'push_for_user', [$userid]);
@@ -707,6 +712,7 @@ public function issue_certificate($userid, $expires = null, array $data = [], $c
$issue->component = $component;
$issue->courseid = $courseid;
$issue->archived = 0;
+ $issue->name = $name;
// Store user fullname.
$data['userfullname'] = fullname($DB->get_record('user', ['id' => $userid]));
@@ -813,6 +819,8 @@ private function send_issue_notification(\stdClass $issue, \stored_file $file):
$userfullname = fullname($user, true);
$mycertificatesurl = new moodle_url('/admin/tool/certificate/my.php');
$subject = get_string('notificationsubjectcertificateissued', 'tool_certificate');
+ $name = $issue->name ?? $this->get_name();
+ $subject = "$name - $subject";
$fullmessage = get_string(
'notificationmsgcertificateissued',
'tool_certificate',
diff --git a/db/install.xml b/db/install.xml
index d0401b27..a0652abf 100644
--- a/db/install.xml
+++ b/db/install.xml
@@ -23,6 +23,7 @@
+
diff --git a/db/upgrade.php b/db/upgrade.php
index e838cd51..4ff8f4ea 100644
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -247,5 +247,18 @@ function xmldb_tool_certificate_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2023071300, 'tool', 'certificate');
}
+ if ($oldversion < 2024061000) {
+ $table = new xmldb_table('tool_certificate_issues');
+ $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '255');
+
+ // Conditionally add field name to tool_certificate_issues.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Certificate savepoint reached.
+ upgrade_plugin_savepoint(true, 2024061000, 'tool', 'certificate');
+ }
+
return true;
}
diff --git a/lang/en/tool_certificate.php b/lang/en/tool_certificate.php
index f132bb53..5702b3e8 100644
--- a/lang/en/tool_certificate.php
+++ b/lang/en/tool_certificate.php
@@ -121,6 +121,7 @@
$string['issueddate'] = 'Date issued';
$string['issuelang'] = 'Issue certificates in user language';
$string['issuelangdesc'] = 'On multi-lingual sites when user language is different from the site language the certificates will be generated in the user\'s language, otherwise all certificates will be generated in the site default language.';
+$string['issuename'] = 'Name (issued)';
$string['issuenotallowed'] = 'You are not allowed to issue certificates from this template.';
$string['issueormangenotallowed'] = 'You are not allowed to issue certificates from or manage this template.';
$string['leftmargin'] = 'Left margin';
diff --git a/tests/certificate_test.php b/tests/certificate_test.php
index de3369d9..52102a21 100644
--- a/tests/certificate_test.php
+++ b/tests/certificate_test.php
@@ -356,6 +356,23 @@ public function test_verify(): void {
$this->assertEquals($result->issue->id, $issueid1);
}
+ /**
+ * Verify a certificate issued with a custom name uses that custom name
+ */
+ public function test_can_set_certificate_name(): void {
+ $testname = 'Test Certificate 1';
+
+ $this->setAdminUser();
+ $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']);
+ $user1 = $this->getDataGenerator()->create_user();
+ $certificate1->issue_certificate($user1->id, null, [], 'tool_certificate', null, $testname);
+
+ $issues = certificate::get_issues_for_template($certificate1->get_id(), 0, 100);
+ $this->assertCount(1, $issues);
+ $issue = reset($issues);
+ $this->assertEquals($testname, $issue->name);
+ }
+
/**
* Test generate code.
*/
diff --git a/version.php b/version.php
index 05777e1c..b8c7dd68 100644
--- a/version.php
+++ b/version.php
@@ -26,7 +26,7 @@
$plugin->component = 'tool_certificate';
$plugin->release = '4.4';
-$plugin->version = 2024052100;
+$plugin->version = 2024061000;
$plugin->requires = 2022041900.00;
$plugin->maturity = MATURITY_STABLE;
$plugin->supported = [400, 404];