. /** * This file contains the customcert date range element. * * @package customcertelement_daterange * @copyright 2018 Dmitrii Metelkin * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace customcertelement_daterange; use \mod_customcert\element_helper; defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); require_once($CFG->dirroot . '/lib/grade/constants.php'); /** * The customcert date range element. * * @package customcertelement_daterange * @copyright 2018 Dmitrii Metelkin * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class element extends \mod_customcert\element { /** * Default max number of dateranges per element. */ const DEFAULT_MAX_RANGES = 10; /** * Date - Issue */ const DATE_ISSUE = 1; /** * Date - Completion */ const DATE_COMPLETION = 2; /** * Date - Course start */ const DATE_COURSE_START = 3; /** * Date - Course end */ const DATE_COURSE_END = 4; /** * Date - Course grade date */ const DATE_COURSE_GRADE = 5; /** * This function renders the form elements when adding a customcert element. * * @param \mod_customcert\edit_element_form $mform the edit_form instance */ public function render_form_elements($mform) { global $COURSE; // Get the possible date options. $dateoptions = array(); $dateoptions[self::DATE_ISSUE] = get_string('issueddate', 'customcertelement_daterange'); $dateoptions[self::DATE_COMPLETION] = get_string('completiondate', 'customcertelement_daterange'); $dateoptions[self::DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_daterange'); $dateoptions[self::DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_daterange'); $dateoptions[self::DATE_COURSE_GRADE] = get_string('coursegradedate', 'customcertelement_daterange'); $dateoptions = $dateoptions + element_helper::get_grade_items($COURSE); $mform->addElement('select', 'dateitem', get_string('dateitem', 'customcertelement_daterange'), $dateoptions); $mform->addHelpButton('dateitem', 'dateitem', 'customcertelement_daterange'); parent::render_form_elements($mform); $mform->addElement('header', 'dateranges', get_string('dateranges', 'customcertelement_daterange')); $mform->addElement('static', 'help', '', get_string('help', 'customcertelement_daterange')); $mform->addElement('text', 'fallbackstring', get_string('fallbackstring', 'customcertelement_daterange')); $mform->addHelpButton('fallbackstring', 'fallbackstring', 'customcertelement_daterange'); $mform->setType('fallbackstring', PARAM_NOTAGS); if (!$maxranges = get_config('customcertelement_daterange', 'maxranges')) { $maxranges = self::DEFAULT_MAX_RANGES; } if (!empty($this->get_data())) { if ($maxranges < $this->get_decoded_data()->numranges) { $maxranges = $this->get_decoded_data()->numranges; } } $mform->addElement('hidden', 'numranges', $maxranges); $mform->setType('numranges', PARAM_INT); for ($i = 0; $i < $maxranges; $i++) { $datarange = array(); $datarange[] = $mform->createElement( 'date_selector', $this->build_element_name('startdate', $i), get_string('start', 'customcertelement_daterange') ); $datarange[] = $mform->createElement( 'date_selector', $this->build_element_name('enddate', $i), get_string('end', 'customcertelement_daterange') ); $datarange[] = $mform->createElement( 'text', $this->build_element_name('datestring', $i), get_string('datestring', 'customcertelement_daterange') ); $datarange[] = $mform->createElement( 'checkbox', $this->build_element_name('enabled', $i), get_string('enable') ); $mform->addElement( 'group', $this->build_element_name('group', $i), get_string('daterange', 'customcertelement_daterange', $i + 1), $datarange, '', false); $mform->disabledIf($this->build_element_name('group', $i), $this->build_element_name('enabled', $i), 'notchecked'); $mform->setType($this->build_element_name('datestring', $i), PARAM_NOTAGS); } } /** * A helper function to build consistent form element name. * * @param string $name * @param string $num * * @return string */ protected function build_element_name($name, $num) { return $name . $num; } /** * Get decoded data stored in DB. * * @return \stdClass */ protected function get_decoded_data() { return json_decode($this->get_data()); } /** * Sets the data on the form when editing an element. * * @param \mod_customcert\edit_element_form $mform the edit_form instance */ public function definition_after_data($mform) { if (!empty($this->get_data()) && !$mform->isSubmitted()) { $element = $mform->getElement('dateitem'); $element->setValue($this->get_decoded_data()->dateitem); $element = $mform->getElement('fallbackstring'); $element->setValue($this->get_decoded_data()->fallbackstring); $element = $mform->getElement('numranges'); $numranges = $element->getValue(); if ($numranges < $this->get_decoded_data()->numranges) { $element->setValue($this->get_decoded_data()->numranges); } foreach ($this->get_decoded_data()->dateranges as $key => $range) { $groupelement = $mform->getElement($this->build_element_name('group', $key)); $groupelements = $groupelement->getElements(); $mform->setDefault($groupelements[0]->getName(), $range->startdate); $mform->setDefault($groupelements[1]->getName(), $range->enddate); $mform->setDefault($groupelements[2]->getName(), $range->datestring); $mform->setDefault($groupelements[3]->getName(), $range->enabled); } } parent::definition_after_data($mform); } /** * Performs validation on the element values. * * @param array $data the submitted data * @param array $files the submitted files * @return array the validation errors */ public function validate_form_elements($data, $files) { $errors = parent::validate_form_elements($data, $files); // Check if at least one range is set. $error = get_string('error:enabled', 'customcertelement_daterange'); for ($i = 0; $i < $data['numranges']; $i++) { if (!empty($data[$this->build_element_name('enabled', $i)])) { $error = ''; } } if (!empty($error)) { $errors['help'] = $error; } // Check that datestring is set for enabled dataranges. for ($i = 0; $i < $data['numranges']; $i++) { $enabled = $this->build_element_name('enabled', $i); $datestring = $this->build_element_name('datestring', $i); if (!empty($data[$enabled]) && empty($data[$datestring])) { $errors[$this->build_element_name('group', $i)] = get_string('error:datestring', 'customcertelement_daterange'); } } // Check that date is correctly set. for ($i = 0; $i < $data['numranges']; $i++) { $enabled = $this->build_element_name('enabled', $i); $startdate = $this->build_element_name('startdate', $i); $enddate = $this->build_element_name('enddate', $i); if (!empty($data[$enabled]) && $data[$startdate] >= $data[$enddate] ) { $errors[$this->build_element_name('group', $i)] = get_string('error:enddate', 'customcertelement_daterange'); } } return $errors; } /** * This will handle how form data will be saved into the data column in the * customcert_elements table. * * @param \stdClass $data the form data * @return string the json encoded array */ public function save_unique_data($data) { $arrtostore = array( 'dateitem' => $data->dateitem, 'fallbackstring' => $data->fallbackstring, 'numranges' => 0, 'dateranges' => [], ); for ($i = 0; $i < $data->numranges; $i++) { $startdate = $this->build_element_name('startdate', $i); $enddate = $this->build_element_name('enddate', $i); $datestring = $this->build_element_name('datestring', $i); $enabled = $this->build_element_name('enabled', $i); if (!empty($data->$datestring)) { $arrtostore['dateranges'][] = [ 'startdate' => $data->$startdate, 'enddate' => $data->$enddate, 'datestring' => $data->$datestring, 'enabled' => !empty($data->$enabled), ]; $arrtostore['numranges']++; } } // Encode these variables before saving into the DB. return json_encode($arrtostore); } /** * Handles rendering the element on the pdf. * * @param \pdf $pdf the pdf object * @param bool $preview true if it is a preview, false otherwise * @param \stdClass $user the user we are rendering this for */ public function render($pdf, $preview, $user) { global $DB; // If there is no element data, we have nothing to display. if (empty($this->get_data())) { return; } $courseid = element_helper::get_courseid($this->id); $dateitem = $this->get_decoded_data()->dateitem; // If we are previewing this certificate then just show a demonstration date. if ($preview) { $date = time(); } else { // Get the page. $page = $DB->get_record('customcert_pages', array('id' => $this->get_pageid()), '*', MUST_EXIST); // Get the customcert this page belongs to. $customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST); // Now we can get the issue for this user. $issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id), '*', MUST_EXIST); switch ($dateitem) { case self::DATE_ISSUE: $date = $issue->timecreated; break; case self::DATE_COMPLETION: // Get the last completion date. $sql = "SELECT MAX(c.timecompleted) as timecompleted FROM {course_completions} c WHERE c.userid = :userid AND c.course = :courseid"; if ($timecompleted = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) { if (!empty($timecompleted->timecompleted)) { $date = $timecompleted->timecompleted; } } break; case self::DATE_COURSE_START: $date = $DB->get_field('course', 'startdate', array('id' => $courseid)); break; case self::DATE_COURSE_END: $date = $DB->get_field('course', 'enddate', array('id' => $courseid)); break; case self::DATE_COURSE_GRADE: $grade = element_helper::get_course_grade_info( $courseid, GRADE_DISPLAY_TYPE_DEFAULT, $user->id ); if ($grade && !empty($grade->get_dategraded())) { $date = $grade->get_dategraded(); } break; default: if (strpos($dateitem, 'gradeitem:') === 0) { $gradeitemid = substr($dateitem, 10); $grade = element_helper::get_grade_item_info( $gradeitemid, $dateitem, $user->id ); } else { $grade = element_helper::get_mod_grade_info( $dateitem, GRADE_DISPLAY_TYPE_DEFAULT, $user->id ); } if ($grade && !empty($grade->get_dategraded())) { $date = $grade->get_dategraded(); } break; } } // Ensure that a date has been set. if (!empty($date)) { element_helper::render_content($pdf, $this, $this->get_daterange_string($date)); } } /** * Get daterange string. * * @param int $date Unix stamp date. * * @return string */ protected function get_daterange_string($date) { $outputstring = ''; foreach ($this->get_decoded_data()->dateranges as $key => $range) { if ($date >= $range->startdate && $date <= $range->enddate) { $outputstring = $range->datestring; } } if (!empty($this->get_decoded_data()->fallbackstring)) { $outputstring = $this->get_decoded_data()->fallbackstring; } return $outputstring; } /** * Render the element in html. * * 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 function render_html() { // If there is no element data, we have nothing to display. if (empty($this->get_data())) { return; } return element_helper::render_html_content($this, get_string('preview', 'customcertelement_daterange', $this->get_name())); } /** * This function is responsible for handling the restoration process of the element. * * We will want to update the course module the date element is pointing to as it will * have changed in the course restore. * * @param \restore_customcert_activity_task $restore */ public function after_restore($restore) { global $DB; $data = $this->get_decoded_data(); if ($newitem = \restore_dbops::get_backup_ids_record($restore->get_restoreid(), 'course_module', $data->dateitem)) { $data->dateitem = $newitem->newitemid; $DB->set_field('customcert_elements', 'data', $this->save_unique_data($data), array('id' => $this->get_id())); } } }