Huge refactor

1) Every certificate is a template. Before a user would create a certificate then had
the option to save it as a template. This could potentially be chaotic with numerous
users creating templates, making the template system a mess. Now, rather than creating
a certificate first, then saving it as a template, you are always creating a template.
Each template is associated with a context, so depending on where you are creating it
the context is different. This means users in the CONTEXT_MODULE context are creating
a template specific to that module, where as a user creating a template in the
CONTEXT_SYSTEM context would be creating a general template that can be used by others.
This meant we can remove the 'customcert_template_*' db tables. Yay - no duplicated
tables.
2) Created new helper classes and moved functionality there.
3) Moved files to classes/ for autoloading.
4) General tidy up.
This commit is contained in:
Mark Nelson 2016-02-16 17:03:34 +08:00
parent 54584a113c
commit 43d20c0d1b
59 changed files with 2028 additions and 1815 deletions

View file

@ -111,7 +111,7 @@ class restore_customcert_activity_task extends restore_activity_task {
// Go through the elements for the certificate.
foreach ($elements as $e) {
// Get an instance of the element class.
if ($e = customcert_get_element_instance($e)) {
if ($e = \mod_customcert\element::instance($e)) {
$e->after_restore($this);
}
}

View file

@ -14,6 +14,8 @@
// 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_customcert;
/**
* Creates an upload form on the settings page.
*
@ -22,12 +24,28 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/mod/customcert/upload_image_form.php');
/**
* Class extends admin setting class to allow/process an uploaded file
*/
class mod_customcert_admin_setting_upload extends admin_setting_configtext {
class admin_setting_link extends \admin_setting_configtext {
/**
* @var string the link.
*/
protected $link;
/**
* @var string the link name.
*/
protected $linkname;
public function __construct($name, $visiblename, $description, $linkname, $link, $defaultsetting,
$paramtype = PARAM_RAW, $size=null) {
$this->link = $link;
$this->linkname = $linkname;
parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
}
/**
* Output the link to the upload image page.
@ -41,7 +59,6 @@ class mod_customcert_admin_setting_upload extends admin_setting_configtext {
$this->config_write($this->name, '');
return format_admin_setting($this, $this->visiblename,
html_writer::link(new moodle_url('/mod/customcert/upload_image.php'), get_string('upload')),
$this->description, true, '', null, $query);
\html_writer::link($this->link, $this->linkname), $this->description, true, '', null, $query);
}
}
}

440
classes/certificate.php Normal file
View file

@ -0,0 +1,440 @@
<?php
// This file is part of the customcert module for 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/>.
/**
* Provides functionality needed by certificates.
*
* @package mod_customcert
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_customcert;
defined('MOODLE_INTERNAL') || die();
/**
* Class element
*
* All customercert element plugins are based on this class.
*/
class certificate {
/**
* @var string the print protection variable
*/
const PROTECTION_PRINT = 'print';
/**
* @var string the modify protection variable
*/
const PROTECTION_MODIFY = 'modify';
/**
* @var string the copy protection variable
*/
const PROTECTION_COPY = 'copy';
/**
* @var int the number of issues that will be displayed on each page in the report
* If you want to display all customcerts on a page set this to 0.
*/
const CUSTOMCERT_PER_PAGE = '20';
/**
* @var int the max number of issues to display
*/
const CUSTOMCERT_MAX_PER_PAGE = '300';
/**
* Handles setting the protection field for the customcert
*
* @param \stdClass $data
* @return string the value to insert into the protection field
*/
public static function set_protection($data) {
$protection = array();
if (!empty($data->protection_print)) {
$protection[] = self::PROTECTION_PRINT;
}
if (!empty($data->protection_modify)) {
$protection[] = self::PROTECTION_MODIFY;
}
if (!empty($data->protection_copy)) {
$protection[] = self::PROTECTION_COPY;
}
// Return the protection string.
return implode(', ', $protection);
}
/**
* Handles uploading an image for the customcert module.
*
* @param int $draftitemid the draft area containing the files
* @param int $contextid the context we are storing this image in
*/
public static function upload_imagefiles($draftitemid, $contextid) {
// Save the file if it exists that is currently in the draft area.
file_save_draft_area_files($draftitemid, $contextid, 'mod_customcert', 'image', 0);
}
/**
* Return the list of possible fonts to use.
*/
public static function get_fonts() {
global $CFG;
// Array to store the available fonts.
$options = array();
// Location of fonts in Moodle.
$fontdir = "$CFG->dirroot/lib/tcpdf/fonts";
// Check that the directory exists.
if (file_exists($fontdir)) {
// Get directory contents.
$fonts = new \DirectoryIterator($fontdir);
// Loop through the font folder.
foreach ($fonts as $font) {
// If it is not a file, or either '.' or '..', or
// the extension is not php, or we can not open file,
// skip it.
if (!$font->isFile() || $font->isDot() || ($font->getExtension() != 'php')) {
continue;
}
// Set the name of the font to null, the include next should then set this
// value, if it is not set then the file does not include the necessary data.
$name = null;
// Some files include a display name, the include next should then set this
// value if it is present, if not then $name is used to create the display name.
$displayname = null;
// Some of the TCPDF files include files that are not present, so we have to
// suppress warnings, this is the TCPDF libraries fault, grrr.
@include("$fontdir/$font");
// If no $name variable in file, skip it.
if (is_null($name)) {
continue;
}
// Remove the extension of the ".php" file that contains the font information.
$filename = basename($font, ".php");
// Check if there is no display name to use.
if (is_null($displayname)) {
// Format the font name, so "FontName-Style" becomes "Font Name - Style".
$displayname = preg_replace("/([a-z])([A-Z])/", "$1 $2", $name);
$displayname = preg_replace("/([a-zA-Z])-([a-zA-Z])/", "$1 - $2", $displayname);
}
$options[$filename] = $displayname;
}
ksort($options);
}
return $options;
}
/**
* Return the list of possible font sizes to use.
*/
public static function get_font_sizes() {
// Array to store the sizes.
$sizes = array();
for ($i = 1; $i <= 60; $i++) {
$sizes[$i] = $i;
}
return $sizes;
}
/**
* Get the time the user has spent in the course.
*
* @param int $courseid
* @return int the total time spent in seconds
*/
public static function get_course_time($courseid) {
global $CFG, $DB, $USER;
$logmanager = get_log_manager();
$readers = $logmanager->get_readers();
$enabledreaders = get_config('tool_log', 'enabled_stores');
$enabledreaders = explode(',', $enabledreaders);
// Go through all the readers until we find one that we can use.
foreach ($enabledreaders as $enabledreader) {
$reader = $readers[$enabledreader];
if ($reader instanceof \logstore_legacy\log\store) {
$logtable = 'log';
$coursefield = 'course';
$timefield = 'time';
break;
} else if ($reader instanceof \core\log\sql_internal_reader) {
$logtable = $reader->get_internal_log_table_name();
$coursefield = 'courseid';
$timefield = 'timecreated';
break;
}
}
// If we didn't find a reader then return 0.
if (!isset($logtable)) {
return 0;
}
$sql = "SELECT id, $timefield
FROM {{$logtable}}
WHERE userid = :userid
AND $coursefield = :courseid
ORDER BY $timefield ASC";
$params = array('userid' => $USER->id, 'courseid' => $courseid);
$totaltime = 0;
if ($logs = $DB->get_recordset_sql($sql, $params)) {
foreach ($logs as $log) {
if (!isset($login)) {
// For the first time $login is not set so the first log is also the first login
$login = $log->$timefield;
$lasthit = $log->$timefield;
$totaltime = 0;
}
$delay = $log->$timefield - $lasthit;
if ($delay > ($CFG->sessiontimeout * 60)) {
// The difference between the last log and the current log is more than
// the timeout Register session value so that we have found a session!
$login = $log->$timefield;
} else {
$totaltime += $delay;
}
// Now the actual log became the previous log for the next cycle
$lasthit = $log->$timefield;
}
return $totaltime;
}
return 0;
}
/**
* Returns a list of issued customcerts.
*
* @param int $customcertid
* @param bool $groupmode are we in group mode
* @param \stdClass $cm the course module
* @param int $page offset
* @param int $perpage total per page
* @return \stdClass the users
*/
public static function get_issues($customcertid, $groupmode, $cm, $page, $perpage) {
global $DB;
// Get the conditional SQL.
list($conditionssql, $conditionsparams) = self::get_conditional_issues_sql($cm, $groupmode);
// If it is empty then return an empty array.
if (empty($conditionsparams)) {
return array();
}
// Add the conditional SQL and the customcertid to form all used parameters.
$allparams = $conditionsparams + array('customcertid' => $customcertid);
// Return the issues.
$sql = "SELECT u.*, ci.code, ci.timecreated
FROM {user} u
INNER JOIN {customcert_issues} ci
ON u.id = ci.userid
WHERE u.deleted = 0
AND ci.customcertid = :customcertid
$conditionssql
ORDER BY " . $DB->sql_fullname();
return $DB->get_records_sql($sql, $allparams, $page * $perpage, $perpage);
}
/**
* Returns the total number of issues for a given customcert.
*
* @param int $customcertid
* @param \stdClass $cm the course module
* @param bool $groupmode the group mode
* @return int the number of issues
*/
public static function get_number_of_issues($customcertid, $cm, $groupmode) {
global $DB;
// Get the conditional SQL.
list($conditionssql, $conditionsparams) = self::get_conditional_issues_sql($cm, $groupmode);
// If it is empty then return 0.
if (empty($conditionsparams)) {
return 0;
}
// Add the conditional SQL and the customcertid to form all used parameters.
$allparams = $conditionsparams + array('customcertid' => $customcertid);
// Return the number of issues.
$sql = "SELECT COUNT(u.id) as count
FROM {user} u
INNER JOIN {customcert_issues} ci
ON u.id = ci.userid
WHERE u.deleted = 0
AND ci.customcertid = :customcertid
$conditionssql";
return $DB->count_records_sql($sql, $allparams);
}
/**
* Returns an array of the conditional variables to use in the get_issues SQL query.
*
* @param \stdClass $cm the course module
* @param bool $groupmode are we in group mode ?
* @return array the conditional variables
*/
public static function get_conditional_issues_sql($cm, $groupmode) {
global $DB, $USER;
// Get all users that can manage this customcert to exclude them from the report.
$context = \context_module::instance($cm->id);
$conditionssql = '';
$conditionsparams = array();
// Get all users that can manage this certificate to exclude them from the report.
$certmanagers = array_keys(get_users_by_capability($context, 'mod/certificate:manage', 'u.id'));
$certmanagers = array_merge($certmanagers, array_keys(get_admins()));
list($sql, $params) = $DB->get_in_or_equal($certmanagers, SQL_PARAMS_NAMED, 'cert');
$conditionssql .= "AND NOT u.id $sql \n";
$conditionsparams += $params;
if ($groupmode) {
$canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
$currentgroup = groups_get_activity_group($cm);
// If we are viewing all participants and the user does not have access to all groups then return nothing.
if (!$currentgroup && !$canaccessallgroups) {
return array('', array());
}
if ($currentgroup) {
if (!$canaccessallgroups) {
// Guest users do not belong to any groups.
if (isguestuser()) {
return array('', array());
}
// Check that the user belongs to the group we are viewing.
$usersgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid);
if ($usersgroups) {
if (!isset($usersgroups[$currentgroup])) {
return array('', array());
}
} else { // They belong to no group, so return an empty array.
return array('', array());
}
}
$groupusers = array_keys(groups_get_members($currentgroup, 'u.*'));
if (empty($groupusers)) {
return array('', array());
}
list($sql, $params) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED, 'grp');
$conditionssql .= "AND u.id $sql ";
$conditionsparams += $params;
}
}
return array($conditionssql, $conditionsparams);
}
/**
* Generates a 10-digit code of random letters and numbers.
*
* @return string
*/
public static function generate_code() {
global $DB;
$uniquecodefound = false;
$code = random_string(10);
while (!$uniquecodefound) {
if (!$DB->record_exists('customcert_issues', array('code' => $code))) {
$uniquecodefound = true;
} else {
$code = random_string(10);
}
}
return $code;
}
/**
* Generate the report.
*
* @param \stdClass $customcert
* @param \stdClass $users the list of users who have had a customcert issued
* @param string $type
*/
public static function generate_report_file($customcert, $users, $type) {
global $CFG, $COURSE;
if ($type == 'ods') {
require_once($CFG->libdir . '/odslib.class.php');
$workbook = new \MoodleODSWorkbook('-');
} else if ($type == 'xls') {
require_once($CFG->libdir . '/excellib.class.php');
$workbook = new \MoodleExcelWorkbook('-');
}
$filename = clean_filename($COURSE->shortname . ' ' . rtrim($customcert->name, '.') . '.' . $type);
// Send HTTP headers.
$workbook->send($filename);
// Creating the first worksheet.
$myxls = $workbook->add_worksheet(get_string('report', 'customcert'));
// Print names of all the fields.
$myxls->write_string(0, 0, get_string('lastname'));
$myxls->write_string(0, 1, get_string('firstname'));
$myxls->write_string(0, 2, get_string('idnumber'));
$myxls->write_string(0, 3, get_string('group'));
$myxls->write_string(0, 4, get_string('receiveddate', 'customcert'));
$myxls->write_string(0, 5, get_string('code', 'customcert'));
// Generate the data for the body of the spreadsheet.
$row = 1;
if ($users) {
foreach ($users as $user) {
$myxls->write_string($row, 0, $user->lastname);
$myxls->write_string($row, 1, $user->firstname);
$studentid = (!empty($user->idnumber)) ? $user->idnumber : ' ';
$myxls->write_string($row, 2, $studentid);
$ug2 = '';
if ($usergrps = groups_get_all_groups($COURSE->id, $user->id)) {
foreach ($usergrps as $ug) {
$ug2 = $ug2 . $ug->name;
}
}
$myxls->write_string($row, 3, $ug2);
$myxls->write_string($row, 4, userdate($user->timecreated));
$myxls->write_string($row, 5, $user->code);
$row++;
}
}
// Close the workbook.
$workbook->close();
}
}

View file

@ -14,13 +14,14 @@
// 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_customcert;
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
require_once($CFG->dirroot . '/course/moodleform_mod.php');
require_once($CFG->dirroot.'/mod/customcert/locallib.php');
require_once($CFG->dirroot . '/mod/customcert/includes/colourpicker.php');
MoodleQuickForm::registerElementType('customcert_colourpicker',
\MoodleQuickForm::registerElementType('customcert_colourpicker',
$CFG->dirroot . '/mod/customcert/includes/colourpicker.php', 'MoodleQuickForm_customcert_colourpicker');
/**
@ -30,12 +31,12 @@ MoodleQuickForm::registerElementType('customcert_colourpicker',
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_customcert_edit_element_form extends moodleform {
class edit_element_form extends \moodleform {
/**
* The element object.
* @var \mod_customcert\element The element object.
*/
private $element;
protected $element;
/**
* Form definition.
@ -52,7 +53,7 @@ class mod_customcert_edit_element_form extends moodleform {
$mform->addRule('name', get_string('required'), 'required', null, 'client');
$mform->addHelpButton('name', 'elementname', 'customcert');
$this->element = customcert_get_element_instance($element);
$this->element = \mod_customcert\element::instance($element);
$this->element->render_form_elements($mform);
$this->add_action_buttons(true);

View file

@ -14,12 +14,14 @@
// 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_customcert;
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
require_once($CFG->dirroot . '/course/moodleform_mod.php');
require_once($CFG->dirroot . '/mod/customcert/includes/colourpicker.php');
MoodleQuickForm::registerElementType('customcert_colourpicker',
\MoodleQuickForm::registerElementType('customcert_colourpicker',
$CFG->dirroot . '/mod/customcert/includes/colourpicker.php', 'MoodleQuickForm_customcert_colourpicker');
/**
@ -29,17 +31,17 @@ MoodleQuickForm::registerElementType('customcert_colourpicker',
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_customcert_edit_form extends moodleform {
class edit_form extends \moodleform {
/**
* The instance id.
* The id of the template being used.
*/
private $id = null;
protected $tid = null;
/**
* The total number of pages for this cert.
*/
private $numpages = 1;
protected $numpages = 1;
/**
* Form definition.
@ -47,16 +49,27 @@ class mod_customcert_edit_form extends moodleform {
public function definition() {
global $DB;
$this->id = $this->_customdata['customcertid'];
$mform =& $this->_form;
$mform->addElement('text', 'name', get_string('name', 'customcert'));
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', null, 'required');
// Get the number of pages for this module.
if ($pages = $DB->get_records('customcert_pages', array('customcertid' => $this->id), 'pagenumber')) {
$this->numpages = count($pages);
foreach ($pages as $p) {
$this->add_customcert_page_elements($p);
if (isset($this->_customdata['tid'])) {
$this->tid = $this->_customdata['tid'];
if ($pages = $DB->get_records('customcert_pages', array('templateid' => $this->tid), 'pagenumber')) {
$this->numpages = count($pages);
foreach ($pages as $p) {
$this->add_customcert_page_elements($p);
}
}
} else { // Add a new template.
// Create a 'fake' page to display the elements on - not yet saved in the DB.
$page = new \stdClass();
$page->id = 1;
$page->pagenumber = 1;
$this->add_customcert_page_elements($page);
}
$mform->closeHeaderBefore('addcertpage');
@ -71,12 +84,9 @@ class mod_customcert_edit_form extends moodleform {
$group[] = $mform->createElement('submit', 'previewbtn', get_string('savechangespreview', 'customcert'));
$mform->addElement('group', 'submitbtngroup', '', $group, '', false);
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->setDefault('id', $this->id);
$mform->addElement('hidden', 'cmid');
$mform->setType('cmid', PARAM_INT);
$mform->setDefault('cmid', $this->_customdata['cmid']);
$mform->addElement('hidden', 'tid');
$mform->setType('tid', PARAM_INT);
$mform->setDefault('tid', $this->tid);
}
/**
@ -88,9 +98,9 @@ class mod_customcert_edit_form extends moodleform {
$mform = $this->_form;
// Check that we are updating a current customcert.
if ($this->id) {
if ($this->tid) {
// Get the pages for this customcert.
if ($pages = $DB->get_records('customcert_pages', array('customcertid' => $this->id))) {
if ($pages = $DB->get_records('customcert_pages', array('templateid' => $this->tid))) {
// Loop through the pages.
foreach ($pages as $p) {
// Set the width.
@ -118,8 +128,17 @@ class mod_customcert_edit_form extends moodleform {
* @return array the errors that were found
*/
public function validation($data, $files) {
global $DB;
$errors = parent::validation($data, $files);
// Check that the template name does not already exist for another template.
if ($template = $DB->get_record('customcert_templates', array('name' => $data['name']))) {
if (empty($data['tid']) || $template->id != $data['tid']) {
$errors['name'] = get_string('customcertnameexists', 'customcert');
}
}
// Go through the data and check any width, height or margin values.
foreach ($data as $key => $value) {
if (strpos($key, 'pagewidth_') !== false) {
@ -158,26 +177,33 @@ class mod_customcert_edit_form extends moodleform {
/**
* Adds the page elements to the form.
*
* @param stdClass $page the customcert page
* @param \stdClass $page the customcert page
*/
private function add_customcert_page_elements($page) {
protected function add_customcert_page_elements($page) {
global $DB, $OUTPUT;
// Create the form object.
$mform =& $this->_form;
$mform->addElement('header', 'page_' . $page->id, get_string('page', 'customcert', $page->pagenumber));
if ($this->numpages > 1) {
$mform->addElement('header', 'page_' . $page->id, get_string('page', 'customcert', $page->pagenumber));
}
$editlink = '/mod/customcert/edit.php';
$editlinkparams = array('tid' => $this->tid);
$editelementlink = '/mod/customcert/edit_element.php';
$editelementlinkparams = array('tid' => $this->tid);
// Place the ordering arrows.
// Only display the move up arrow if it is not the first.
if ($page->pagenumber > 1) {
$url = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'moveup' => $page->id));
$mform->addElement('html', $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('moveup'))));
$url = new \moodle_url($editlink, $editlinkparams + array('moveup' => $page->id));
$mform->addElement('html', $OUTPUT->action_icon($url, new \pix_icon('t/up', get_string('moveup'))));
}
// Only display the move down arrow if it is not the last.
if ($page->pagenumber < $this->numpages) {
$url = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'movedown' => $page->id));
$mform->addElement('html', $OUTPUT->action_icon($url, new pix_icon('t/down', get_string('movedown'))));
$url = new \moodle_url($editlink, $editlinkparams + array('movedown' => $page->id));
$mform->addElement('html', $OUTPUT->action_icon($url, new \pix_icon('t/down', get_string('movedown'))));
}
$mform->addElement('text', 'pagewidth_' . $page->id, get_string('width', 'customcert'));
@ -194,14 +220,16 @@ class mod_customcert_edit_form extends moodleform {
$mform->addElement('text', 'pageleftmargin_' . $page->id, get_string('leftmargin', 'customcert'));
$mform->setType('pageleftmargin_' . $page->id, PARAM_INT);
$mform->setDefault('pageleftmargin_' . $page->id, 0);
$mform->addHelpButton('pageleftmargin_' . $page->id, 'leftmargin', 'customcert');
$mform->addElement('text', 'pagerightmargin_' . $page->id, get_string('rightmargin', 'customcert'));
$mform->setType('pagerightmargin_' . $page->id, PARAM_INT);
$mform->setDefault('pagerightmargin_' . $page->id, 0);
$mform->addHelpButton('pagerightmargin_' . $page->id, 'rightmargin', 'customcert');
$group = array();
$group[] = $mform->createElement('select', 'element_' . $page->id, '', customcert_get_elements());
$group[] = $mform->createElement('select', 'element_' . $page->id, '', element::get_available_types());
$group[] = $mform->createElement('submit', 'addelement_' . $page->id, get_string('addelement', 'customcert'));
$mform->addElement('group', 'elementgroup', '', $group, '', false);
@ -210,7 +238,7 @@ class mod_customcert_edit_form extends moodleform {
// Get the total number of elements.
$numelements = count($elements);
// Create a table to display these elements.
$table = new html_table();
$table = new \html_table();
$table->head = array(get_string('name', 'customcert'), get_string('type', 'customcert'), '');
$table->align = array('left', 'left', 'center');
// If we have more than one element then we can change the order, so add extra column for the up and down arrow.
@ -220,29 +248,29 @@ class mod_customcert_edit_form extends moodleform {
}
// Loop through and add the elements to the table.
foreach ($elements as $element) {
$row = new html_table_row();
$row = new \html_table_row();
$row->cells[] = $element->name;
$row->cells[] = $element->element;
// Link to edit this element.
$editlink = new moodle_url('/mod/customcert/edit_element.php', array('id' => $element->id,
'cmid' => $this->_customdata['cmid'],
$link = new \moodle_url($editelementlink, $editelementlinkparams + array('id' => $element->id,
'action' => 'edit'));
$icons = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit')));
$icons = $OUTPUT->action_icon($link, new \pix_icon('t/edit', get_string('edit')));
// Link to delete the element.
$deletelink = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'deleteelement' => $element->id));
$icons .= $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('delete', 'customcert')));
$link = new \moodle_url($editlink, $editlinkparams + array('id' => $element->id,
'deleteelement' => $element->id));
$icons .= $OUTPUT->action_icon($link, new \pix_icon('t/delete', get_string('delete')));
// Now display any moving arrows if they are needed.
if ($numelements > 1) {
// Only display the move up arrow if it is not the first.
$moveicons = '';
if ($element->sequence > 1) {
$url = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'emoveup' => $element->id));
$moveicons .= $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('moveup')));
$url = new \moodle_url($editlink, $editlinkparams + array('emoveup' => $element->id));
$moveicons .= $OUTPUT->action_icon($url, new \pix_icon('t/up', get_string('moveup')));
}
// Only display the move down arrow if it is not the last.
if ($element->sequence < $numelements) {
$url = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'emovedown' => $element->id));
$moveicons .= $OUTPUT->action_icon($url, new pix_icon('t/down', get_string('movedown')));
$url = new \moodle_url($editlink, $editlinkparams + array('emovedown' => $element->id));
$moveicons .= $OUTPUT->action_icon($url, new \pix_icon('t/down', get_string('movedown')));
}
$icons .= $moveicons;
}
@ -250,20 +278,20 @@ class mod_customcert_edit_form extends moodleform {
$table->data[] = $row;
}
// Create link to order the elements.
$link = html_writer::link(new moodle_url('/mod/customcert/rearrange.php', array('id' => $page->id)),
get_string('rearrangeelements', 'customcert'));
$link = \html_writer::link(new \moodle_url('/mod/customcert/rearrange.php', array('pid' => $page->id)),
get_string('rearrangeelements', 'customcert'));
// Add the table to the form.
$mform->addElement('static', 'elements_' . $page->id, get_string('elements', 'customcert'), html_writer::table($table)
. html_writer::tag( 'div', $link, array('style' => 'text-align:right')));
$mform->addElement('static', 'elements_' . $page->id, get_string('elements', 'customcert'), \html_writer::table($table)
. \html_writer::tag( 'div', $link, array('style' => 'text-align:right')));
$mform->addHelpButton('elements_' . $page->id, 'elements', 'customcert');
}
// Add option to delete this page if there is more than one page.
if ($this->numpages > 1) {
// Link to delete the element.
$deletelink = new moodle_url('/mod/customcert/edit.php', array('cmid' => $this->_customdata['cmid'], 'deletepage' => $page->id));
$deletelink = html_writer::tag('a', get_string('deletecertpage', 'customcert'), array('href' => $deletelink->out(false), 'class' => 'deletebutton'));
$mform->addElement('html', html_writer::tag('div', $deletelink, array('class' => 'deletebutton')));
$deletelink = new \moodle_url($editlink, $editlinkparams + array('deletepage' => $page->id));
$deletelink = \html_writer::tag('a', get_string('deletecertpage', 'customcert'), array('href' => $deletelink->out(false), 'class' => 'deletebutton'));
$mform->addElement('html', \html_writer::tag('div', $deletelink, array('class' => 'deletebutton')));
}
}
}

View file

@ -34,7 +34,7 @@ defined('MOODLE_INTERNAL') || die();
abstract class element {
/**
* The data for the element we are adding.
* @var \stdClass $element The data for the element we are adding.
*/
public $element;
@ -51,20 +51,20 @@ abstract class element {
* This function renders the form elements when adding a customcert element.
* Can be overridden if more functionality is needed.
*
* @param \mod_customcert_edit_element_form $mform the edit_form instance.
* @param edit_element_form $mform the edit_form instance.
*/
public function render_form_elements($mform) {
// Render the common elements.
$this->render_form_element_font($mform);
$this->render_form_element_colour($mform);
$this->render_form_element_position($mform);
element_helper::render_form_element_font($mform);
element_helper::render_form_element_colour($mform);
element_helper::render_form_element_position($mform);
}
/**
* Sets the data on the form when editing an element.
* Can be overridden if more functionality is needed.
*
* @param \mod_customcert_edit_element_form $mform the edit_form instance
* @param edit_element_form $mform the edit_form instance
*/
public function definition_after_data($mform) {
// Loop through the properties of the element and set the values
@ -90,8 +90,8 @@ abstract class element {
$errors = array();
// Common validation methods.
$errors += $this->validate_form_element_colour($data);
$errors += $this->validate_form_element_position($data);
$errors += element_helper::validate_form_element_colour($data);
$errors += element_helper::validate_form_element_position($data);
return $errors;
}
@ -125,7 +125,7 @@ abstract class element {
} else { // Must be adding a new one.
$element->element = $data->element;
$element->pageid = $data->pageid;
$element->sequence = $this->get_element_sequence($element->pageid);
$element->sequence = \mod_customcert\element_helper::get_element_sequence($element->pageid);
$element->timecreated = time();
$DB->insert_record('customcert_elements', $element);
}
@ -133,7 +133,7 @@ abstract class element {
/**
* This will handle how form data will be saved into the data column in the
* customcert column.
* customcert_elements table.
* Can be overridden if more functionality is needed.
*
* @param \stdClass $data the form data
@ -144,31 +144,19 @@ abstract class element {
}
/**
* This will handle how individual elements save their data
* to a template to be loaded later.
* This handles copying data from another element of the same type.
* Can be overridden if more functionality is needed.
*
* @param \stdClass $data the form data
* @return bool returns true if the data was saved to the template, false otherwise
* @return bool returns true if the data was copied successfully, false otherwise
*/
public function save_data_to_template($data) {
return true;
}
/**
* This will handle how individual elements load their data
* from a template to an existing customcert.
* Can be overridden if more functionality is needed.
*
* @param \stdClass $data the form data
* @return bool returns true if the data was loaded from the template, false otherwise
*/
public function load_data_from_template($data) {
public function copy_element($data) {
return true;
}
/**
* Handles rendering the element on the pdf.
*
* Must be overridden.
*
* @param \pdf $pdf the pdf object
@ -176,56 +164,6 @@ abstract class element {
*/
public abstract function render($pdf, $preview);
/**
* Common behaviour for rendering specified content on the pdf.
*
* @param \pdf $pdf the pdf object
* @param string $content the content to render
*/
public function render_content($pdf, $content) {
list($font, $attr) = $this->get_font();
$pdf->setFont($font, $attr, $this->element->size);
$fontcolour = \TCPDF_COLORS::convertHTMLColorToDec($this->element->colour, $fontcolour);
$pdf->SetTextColor($fontcolour['R'], $fontcolour['G'], $fontcolour['B']);
$x = $this->element->posx;
$y = $this->element->posy;
$w = $this->element->width;
$refpoint = $this->element->refpoint;
$actualwidth = $pdf->GetStringWidth($content);
if ($w and $w < $actualwidth) {
$actualwidth = $w;
}
switch ($refpoint) {
case CUSTOMCERT_REF_POINT_TOPRIGHT:
$x = $this->element->posx - $actualwidth;
if ($x < 0) {
$x = 0;
$w = $this->element->posx;
} else {
$w = $actualwidth;
}
break;
case CUSTOMCERT_REF_POINT_TOPCENTER:
$x = $this->element->posx - $actualwidth / 2;
if ($x < 0) {
$x = 0;
$w = $this->element->posx * 2;
} else {
$w = $actualwidth;
}
break;
}
if ($w) {
$w += 0.0001;
}
$pdf->setCellPaddings(0, 0, 0, 0);
$pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true);
}
/**
* Render the element in html.
*
@ -233,27 +171,11 @@ abstract class element {
*
* This function is used to render the element when we are using the
* drag and drop interface to position it.
*
* @return string the html
*/
public abstract function render_html();
/**
* Common behaviour for rendering specified content on the drag and drop page.
*
* @param string $content the content to render
* @return string the html
*/
public function render_html_content($content) {
list($font, $attr) = $this->get_font();
$fontstyle = 'font-family: ' . $font;
if (strpos($attr, 'B') !== false) {
$fontstyle .= ': font-weight: bold';
}
if (strpos($attr, 'I') !== false) {
$fontstyle .= ': font-style: italic';
}
$style = $fontstyle . '; color: ' . $this->element->colour . '; font-size: ' . $this->element->size . 'pt';
return \html_writer::tag('span', $content, array('style' => $style));
}
/**
* Handles deleting any data this element may have introduced.
@ -261,174 +183,12 @@ abstract class element {
*
* @return bool success return true if deletion success, false otherwise
*/
public function delete_element() {
public function delete() {
global $DB;
return $DB->delete_records('customcert_elements', array('id' => $this->element->id));
}
/**
* Helper function that returns the sequence on a specified customcert page for a
* newly created element.
*
* @param int $pageid the id of the page we are adding this element to
* @return int the element number
*/
public static function get_element_sequence($pageid) {
global $DB;
// Set the sequence of the element we are creating.
$sequence = 1;
// Check if there already elements that exist, if so, overwrite value.
$sql = "SELECT MAX(sequence) as maxsequence
FROM {customcert_elements}
WHERE pageid = :id";
// Get the current max sequence on this page and add 1 to get the new sequence.
if ($maxseq = $DB->get_record_sql($sql, array('id' => $pageid))) {
$sequence = $maxseq->maxsequence + 1;
}
return $sequence;
}
/**
* Helper function to render the font elements.
*
* @param \mod_customcert_edit_element_form $mform the edit_form instance.
*/
public function render_form_element_font($mform) {
$mform->addElement('select', 'font', get_string('font', 'customcert'), customcert_get_fonts());
$mform->setType('font', PARAM_TEXT);
$mform->setDefault('font', 'times');
$mform->addHelpButton('font', 'font', 'customcert');
$mform->addElement('select', 'size', get_string('fontsize', 'customcert'), customcert_get_font_sizes());
$mform->setType('size', PARAM_INT);
$mform->setDefault('size', 12);
$mform->addHelpButton('size', 'fontsize', 'customcert');
}
/**
* Helper function to render the colour elements.
*
* @param \mod_customcert_edit_element_form $mform the edit_form instance.
*/
public function render_form_element_colour($mform) {
$mform->addElement('customcert_colourpicker', 'colour', get_string('fontcolour', 'customcert'));
$mform->setType('colour', PARAM_RAW); // Need to validate that this is a valid colour.
$mform->setDefault('colour', '#000000');
$mform->addHelpButton('colour', 'fontcolour', 'customcert');
}
/**
* Helper function to render the position elements.
*
* @param \mod_customcert_edit_element_form $mform the edit_form instance.
*/
public function render_form_element_position($mform) {
$mform->addElement('text', 'posx', get_string('posx', 'customcert'), array('size' => 10));
$mform->setType('posx', PARAM_INT);
$mform->setDefault('posx', 0);
$mform->addHelpButton('posx', 'posx', 'customcert');
$mform->addElement('text', 'posy', get_string('posy', 'customcert'), array('size' => 10));
$mform->setType('posy', PARAM_INT);
$mform->setDefault('posy', 0);
$mform->addHelpButton('posy', 'posy', 'customcert');
$mform->addElement('text', 'width', get_string('elementwidth', 'customcert'), array('size' => 10));
$mform->setType('width', PARAM_INT);
$mform->setDefault('width', 0);
$mform->addHelpButton('width', 'elementwidth', 'customcert');
$refpointoptions = array();
$refpointoptions[CUSTOMCERT_REF_POINT_TOPLEFT] = get_string('topleft', 'customcert');
$refpointoptions[CUSTOMCERT_REF_POINT_TOPCENTER] = get_string('topcenter', 'customcert');
$refpointoptions[CUSTOMCERT_REF_POINT_TOPRIGHT] = get_string('topright', 'customcert');
$mform->addElement('select', 'refpoint', get_string('refpoint', 'customcert'), $refpointoptions);
$mform->setType('refpoint', PARAM_INT);
$mform->setDefault('refpoint', CUSTOMCERT_REF_POINT_TOPCENTER);
$mform->addHelpButton('refpoint', 'refpoint', 'customcert');
}
/**
* Helper function to performs validation on the colour element.
*
* @param array $data the submitted data
* @return array the validation errors
*/
public function validate_form_element_colour($data) {
$errors = array();
// Validate the colour.
if (!$this->validate_colour($data['colour'])) {
$errors['colour'] = get_string('invalidcolour', 'customcert');
}
return $errors;
}
/**
* Helper function to performs validation on the position elements.
*
* @param array $data the submitted data
* @return array the validation errors
*/
public function validate_form_element_position($data) {
$errors = array();
// Check if posx is not set, or not numeric or less than 0.
if ((!isset($data['posx'])) || (!is_numeric($data['posx'])) || ($data['posx'] < 0)) {
$errors['posx'] = get_string('invalidposition', 'customcert', 'X');
}
// Check if posy is not set, or not numeric or less than 0.
if ((!isset($data['posy'])) || (!is_numeric($data['posy'])) || ($data['posy'] < 0)) {
$errors['posy'] = get_string('invalidposition', 'customcert', 'Y');
}
// Check if width is less than 0.
if (isset($data['width']) && $data['width'] < 0) {
$errors['width'] = get_string('invalidelementwidth', 'customcert');
}
return $errors;
}
/**
* Returns the font used for this element.
*
* @return array the font and font attributes
*/
public function get_font() {
// Variable for the font.
$font = $this->element->font;
// Get the last two characters of the font name.
$fontlength = strlen($font);
$lastchar = $font[$fontlength - 1];
$secondlastchar = $font[$fontlength - 2];
// The attributes of the font.
$attr = '';
// Check if the last character is 'i'.
if ($lastchar == 'i') {
// Remove the 'i' from the font name.
$font = substr($font, 0, -1);
// Check if the second last char is b.
if ($secondlastchar == 'b') {
// Remove the 'b' from the font name.
$font = substr($font, 0, -1);
$attr .= 'B';
}
$attr .= 'I';
} else if ($lastchar == 'b') {
// Remove the 'b' from the font name.
$font = substr($font, 0, -1);
$attr .= 'B';
}
return array($font, $attr);
}
/**
* This function is responsible for handling the restoration process of the element.
*
@ -438,58 +198,74 @@ abstract class element {
*
* @param \restore_customcert_activity_task $restore
*/
public function after_restore($restore) {
public function after_restore($restore) { }
/**
* Magic getter for read only access.
*
* @param string $name
*/
public function __get($name) {
if (property_exists($this->element, $name)) {
return $this->element->$name;
}
}
/**
* Validates the colour selected.
* Returns an instance of the element class.
*
* @param string $colour
* @return bool returns true if the colour is valid, false otherwise
* @param \stdClass $element the element
* @return \mod_customcert\element|bool returns the instance of the element class, or false if element
* class does not exists.
*/
protected function validate_colour($colour) {
// List of valid HTML colour names.
$colournames = array(
'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson',
'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray',
'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta',
'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick',
'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro',
'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green',
'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen',
'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen',
'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue',
'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
'lime', 'limegreen', 'linen', 'magenta', 'maroon',
'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive',
'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod',
'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip',
'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan',
'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white',
'whitesmoke', 'yellow', 'yellowgreen'
);
public static function instance($element) {
// Get the class name.
$classname = '\\customcertelement_' . $element->element . '\\element';
if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $colour)) {
return true;
} else if (in_array(strtolower($colour), $colournames)) {
return true;
// Ensure the necessary class exists.
if (class_exists($classname)) {
return new $classname($element);
}
return false;
}
/**
* Return the list of possible elements to add.
*
* @return array the list of element types that can be used.
*/
public static function get_available_types() {
global $CFG;
// Array to store the element types.
$options = array();
// Check that the directory exists.
$elementdir = "$CFG->dirroot/mod/customcert/element";
if (file_exists($elementdir)) {
// Get directory contents.
$elementfolders = new \DirectoryIterator($elementdir);
// Loop through the elements folder.
foreach ($elementfolders as $elementfolder) {
// If it is not a directory or it is '.' or '..', skip it.
if (!$elementfolder->isDir() || $elementfolder->isDot()) {
continue;
}
// Check that the standard class exists, if not we do
// not want to display it as an option as it will not work.
$foldername = $elementfolder->getFilename();
// Get the class name.
$classname = '\\customcertelement_' . $foldername . '\\element';
// Ensure the necessary class exists.
if (class_exists($classname)) {
$component = "customcertelement_{$foldername}";
$options[$foldername] = get_string('pluginname', $component);
}
}
}
\core_collator::asort($options);
return $options;
}
}

325
classes/element_helper.php Normal file
View file

@ -0,0 +1,325 @@
<?php
// This file is part of the customcert module for 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/>.
/**
* Provides useful functions related to elements.
*
* @package mod_customcert
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_customcert;
defined('MOODLE_INTERNAL') || die();
/**
* Class helper.
*
* Provides useful functions related to elements.
*/
class element_helper {
/**
* @var int the top-left of element
*/
const CUSTOMCERT_REF_POINT_TOPLEFT = 0;
/**
* @var int the top-center of element
*/
const CUSTOMCERT_REF_POINT_TOPCENTER = 1;
/**
* @var int the top-left of element
*/
const CUSTOMCERT_REF_POINT_TOPRIGHT = 2;
/**
* Common behaviour for rendering specified content on the pdf.
*
* @param \pdf $pdf the pdf object
* @param \mod_customcert\element $element the customcert element
* @param string $content the content to render
*/
public static function render_content($pdf, $element, $content) {
list($font, $attr) = \mod_customcert\element_helper::get_font($element);
$pdf->setFont($font, $attr, $element->size);
$fontcolour = \TCPDF_COLORS::convertHTMLColorToDec($element->colour, $fontcolour);
$pdf->SetTextColor($fontcolour['R'], $fontcolour['G'], $fontcolour['B']);
$x = $element->posx;
$y = $element->posy;
$w = $element->width;
$refpoint = $element->refpoint;
$actualwidth = $pdf->GetStringWidth($content);
if ($w and $w < $actualwidth) {
$actualwidth = $w;
}
switch ($refpoint) {
case self::CUSTOMCERT_REF_POINT_TOPRIGHT:
$x = $element->posx - $actualwidth;
if ($x < 0) {
$x = 0;
$w = $element->posx;
} else {
$w = $actualwidth;
}
break;
case self::CUSTOMCERT_REF_POINT_TOPCENTER:
$x = $element->posx - $actualwidth / 2;
if ($x < 0) {
$x = 0;
$w = $element->posx * 2;
} else {
$w = $actualwidth;
}
break;
}
if ($w) {
$w += 0.0001;
}
$pdf->setCellPaddings(0, 0, 0, 0);
$pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true);
}