/mod/data/lib.php
PHP | 4839 lines | 3061 code | 604 blank | 1174 comment | 655 complexity | 539a26e2f838423c139dc3db3e782919 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
Large files files are truncated, but you can click here to view the full file
- <?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/>.
- /**
- * @package mod_data
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- defined('MOODLE_INTERNAL') || die();
- // Some constants
- define ('DATA_MAX_ENTRIES', 50);
- define ('DATA_PERPAGE_SINGLE', 1);
- define ('DATA_FIRSTNAME', -1);
- define ('DATA_LASTNAME', -2);
- define ('DATA_APPROVED', -3);
- define ('DATA_TIMEADDED', 0);
- define ('DATA_TIMEMODIFIED', -4);
- define ('DATA_TAGS', -5);
- define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
- // Users having assigned the default role "Non-editing teacher" can export database records
- // Using the mod/data capability "viewalluserpresets" existing in Moodle 1.9.x.
- // In Moodle >= 2, new roles may be introduced and used instead.
- define('DATA_PRESET_COMPONENT', 'mod_data');
- define('DATA_PRESET_FILEAREA', 'site_presets');
- define('DATA_PRESET_CONTEXT', SYSCONTEXTID);
- define('DATA_EVENT_TYPE_OPEN', 'open');
- define('DATA_EVENT_TYPE_CLOSE', 'close');
- require_once(__DIR__ . '/deprecatedlib.php');
- /**
- * @package mod_data
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class data_field_base { // Base class for Database Field Types (see field/*/field.class.php)
- /** @var string Subclasses must override the type with their name */
- var $type = 'unknown';
- /** @var object The database object that this field belongs to */
- var $data = NULL;
- /** @var object The field object itself, if we know it */
- var $field = NULL;
- /** @var int Width of the icon for this fieldtype */
- var $iconwidth = 16;
- /** @var int Width of the icon for this fieldtype */
- var $iconheight = 16;
- /** @var object course module or cmifno */
- var $cm;
- /** @var object activity context */
- var $context;
- /** @var priority for globalsearch indexing */
- protected static $priority = self::NO_PRIORITY;
- /** priority value for invalid fields regarding indexing */
- const NO_PRIORITY = 0;
- /** priority value for minimum priority */
- const MIN_PRIORITY = 1;
- /** priority value for low priority */
- const LOW_PRIORITY = 2;
- /** priority value for high priority */
- const HIGH_PRIORITY = 3;
- /** priority value for maximum priority */
- const MAX_PRIORITY = 4;
- /**
- * Constructor function
- *
- * @global object
- * @uses CONTEXT_MODULE
- * @param int $field
- * @param int $data
- * @param int $cm
- */
- function __construct($field=0, $data=0, $cm=0) { // Field or data or both, each can be id or object
- global $DB;
- if (empty($field) && empty($data)) {
- print_error('missingfield', 'data');
- }
- if (!empty($field)) {
- if (is_object($field)) {
- $this->field = $field; // Programmer knows what they are doing, we hope
- } else if (!$this->field = $DB->get_record('data_fields', array('id'=>$field))) {
- print_error('invalidfieldid', 'data');
- }
- if (empty($data)) {
- if (!$this->data = $DB->get_record('data', array('id'=>$this->field->dataid))) {
- print_error('invalidid', 'data');
- }
- }
- }
- if (empty($this->data)) { // We need to define this properly
- if (!empty($data)) {
- if (is_object($data)) {
- $this->data = $data; // Programmer knows what they are doing, we hope
- } else if (!$this->data = $DB->get_record('data', array('id'=>$data))) {
- print_error('invalidid', 'data');
- }
- } else { // No way to define it!
- print_error('missingdata', 'data');
- }
- }
- if ($cm) {
- $this->cm = $cm;
- } else {
- $this->cm = get_coursemodule_from_instance('data', $this->data->id);
- }
- if (empty($this->field)) { // We need to define some default values
- $this->define_default_field();
- }
- $this->context = context_module::instance($this->cm->id);
- }
- /**
- * This field just sets up a default field object
- *
- * @return bool
- */
- function define_default_field() {
- global $OUTPUT;
- if (empty($this->data->id)) {
- echo $OUTPUT->notification('Programmer error: dataid not defined in field class');
- }
- $this->field = new stdClass();
- $this->field->id = 0;
- $this->field->dataid = $this->data->id;
- $this->field->type = $this->type;
- $this->field->param1 = '';
- $this->field->param2 = '';
- $this->field->param3 = '';
- $this->field->name = '';
- $this->field->description = '';
- $this->field->required = false;
- return true;
- }
- /**
- * Set up the field object according to data in an object. Now is the time to clean it!
- *
- * @return bool
- */
- function define_field($data) {
- $this->field->type = $this->type;
- $this->field->dataid = $this->data->id;
- $this->field->name = trim($data->name);
- $this->field->description = trim($data->description);
- $this->field->required = !empty($data->required) ? 1 : 0;
- if (isset($data->param1)) {
- $this->field->param1 = trim($data->param1);
- }
- if (isset($data->param2)) {
- $this->field->param2 = trim($data->param2);
- }
- if (isset($data->param3)) {
- $this->field->param3 = trim($data->param3);
- }
- if (isset($data->param4)) {
- $this->field->param4 = trim($data->param4);
- }
- if (isset($data->param5)) {
- $this->field->param5 = trim($data->param5);
- }
- return true;
- }
- /**
- * Insert a new field in the database
- * We assume the field object is already defined as $this->field
- *
- * @global object
- * @return bool
- */
- function insert_field() {
- global $DB, $OUTPUT;
- if (empty($this->field)) {
- echo $OUTPUT->notification('Programmer error: Field has not been defined yet! See define_field()');
- return false;
- }
- $this->field->id = $DB->insert_record('data_fields',$this->field);
- // Trigger an event for creating this field.
- $event = \mod_data\event\field_created::create(array(
- 'objectid' => $this->field->id,
- 'context' => $this->context,
- 'other' => array(
- 'fieldname' => $this->field->name,
- 'dataid' => $this->data->id
- )
- ));
- $event->trigger();
- return true;
- }
- /**
- * Update a field in the database
- *
- * @global object
- * @return bool
- */
- function update_field() {
- global $DB;
- $DB->update_record('data_fields', $this->field);
- // Trigger an event for updating this field.
- $event = \mod_data\event\field_updated::create(array(
- 'objectid' => $this->field->id,
- 'context' => $this->context,
- 'other' => array(
- 'fieldname' => $this->field->name,
- 'dataid' => $this->data->id
- )
- ));
- $event->trigger();
- return true;
- }
- /**
- * Delete a field completely
- *
- * @global object
- * @return bool
- */
- function delete_field() {
- global $DB;
- if (!empty($this->field->id)) {
- // Get the field before we delete it.
- $field = $DB->get_record('data_fields', array('id' => $this->field->id));
- $this->delete_content();
- $DB->delete_records('data_fields', array('id'=>$this->field->id));
- // Trigger an event for deleting this field.
- $event = \mod_data\event\field_deleted::create(array(
- 'objectid' => $this->field->id,
- 'context' => $this->context,
- 'other' => array(
- 'fieldname' => $this->field->name,
- 'dataid' => $this->data->id
- )
- ));
- $event->add_record_snapshot('data_fields', $field);
- $event->trigger();
- }
- return true;
- }
- /**
- * Print the relevant form element in the ADD template for this field
- *
- * @global object
- * @param int $recordid
- * @return string
- */
- function display_add_field($recordid=0, $formdata=null) {
- global $DB, $OUTPUT;
- if ($formdata) {
- $fieldname = 'field_' . $this->field->id;
- $content = $formdata->$fieldname;
- } else if ($recordid) {
- $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
- } else {
- $content = '';
- }
- // beware get_field returns false for new, empty records MDL-18567
- if ($content===false) {
- $content='';
- }
- $str = '<div title="' . s($this->field->description) . '">';
- $str .= '<label for="field_'.$this->field->id.'"><span class="accesshide">'.$this->field->name.'</span>';
- if ($this->field->required) {
- $image = $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
- $str .= html_writer::div($image, 'inline-req');
- }
- $str .= '</label><input class="basefieldinput form-control d-inline mod-data-input" ' .
- 'type="text" name="field_' . $this->field->id . '" ' .
- 'id="field_' . $this->field->id . '" value="' . s($content) . '" />';
- $str .= '</div>';
- return $str;
- }
- /**
- * Print the relevant form element to define the attributes for this field
- * viewable by teachers only.
- *
- * @global object
- * @global object
- * @return void Output is echo'd
- */
- function display_edit_field() {
- global $CFG, $DB, $OUTPUT;
- if (empty($this->field)) { // No field has been defined yet, try and make one
- $this->define_default_field();
- }
- echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
- echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
- echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
- if (empty($this->field->id)) {
- echo '<input type="hidden" name="mode" value="add" />'."\n";
- $savebutton = get_string('add');
- } else {
- echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
- echo '<input type="hidden" name="mode" value="update" />'."\n";
- $savebutton = get_string('savechanges');
- }
- echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
- echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
- echo $OUTPUT->heading($this->name(), 3);
- require_once($CFG->dirroot.'/mod/data/field/'.$this->type.'/mod.html');
- echo html_writer::start_div('mt-3');
- echo html_writer::tag('input', null, array('type' => 'submit', 'value' => $savebutton,
- 'class' => 'btn btn-primary'));
- echo html_writer::tag('input', null, array('type' => 'submit', 'name' => 'cancel',
- 'value' => get_string('cancel'), 'class' => 'btn btn-secondary ml-2'));
- echo html_writer::end_div();
- echo '</form>';
- echo $OUTPUT->box_end();
- }
- /**
- * Display the content of the field in browse mode
- *
- * @global object
- * @param int $recordid
- * @param object $template
- * @return bool|string
- */
- function display_browse_field($recordid, $template) {
- global $DB;
- if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
- if (isset($content->content)) {
- $options = new stdClass();
- if ($this->field->param1 == '1') { // We are autolinking this field, so disable linking within us
- //$content->content = '<span class="nolink">'.$content->content.'</span>';
- //$content->content1 = FORMAT_HTML;
- $options->filter=false;
- }
- $options->para = false;
- $str = format_text($content->content, $content->content1, $options);
- } else {
- $str = '';
- }
- return $str;
- }
- return false;
- }
- /**
- * Update the content of one data field in the data_content table
- * @global object
- * @param int $recordid
- * @param mixed $value
- * @param string $name
- * @return bool
- */
- function update_content($recordid, $value, $name=''){
- global $DB;
- $content = new stdClass();
- $content->fieldid = $this->field->id;
- $content->recordid = $recordid;
- $content->content = clean_param($value, PARAM_NOTAGS);
- if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
- $content->id = $oldcontent->id;
- return $DB->update_record('data_content', $content);
- } else {
- return $DB->insert_record('data_content', $content);
- }
- }
- /**
- * Delete all content associated with the field
- *
- * @global object
- * @param int $recordid
- * @return bool
- */
- function delete_content($recordid=0) {
- global $DB;
- if ($recordid) {
- $conditions = array('fieldid'=>$this->field->id, 'recordid'=>$recordid);
- } else {
- $conditions = array('fieldid'=>$this->field->id);
- }
- $rs = $DB->get_recordset('data_content', $conditions);
- if ($rs->valid()) {
- $fs = get_file_storage();
- foreach ($rs as $content) {
- $fs->delete_area_files($this->context->id, 'mod_data', 'content', $content->id);
- }
- }
- $rs->close();
- return $DB->delete_records('data_content', $conditions);
- }
- /**
- * Check if a field from an add form is empty
- *
- * @param mixed $value
- * @param mixed $name
- * @return bool
- */
- function notemptyfield($value, $name) {
- return !empty($value);
- }
- /**
- * Just in case a field needs to print something before the whole form
- */
- function print_before_form() {
- }
- /**
- * Just in case a field needs to print something after the whole form
- */
- function print_after_form() {
- }
- /**
- * Returns the sortable field for the content. By default, it's just content
- * but for some plugins, it could be content 1 - content4
- *
- * @return string
- */
- function get_sort_field() {
- return 'content';
- }
- /**
- * Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
- *
- * @param string $fieldname
- * @return string $fieldname
- */
- function get_sort_sql($fieldname) {
- return $fieldname;
- }
- /**
- * Returns the name/type of the field
- *
- * @return string
- */
- function name() {
- return get_string('fieldtypelabel', "datafield_$this->type");
- }
- /**
- * Prints the respective type icon
- *
- * @global object
- * @return string
- */
- function image() {
- global $OUTPUT;
- $params = array('d'=>$this->data->id, 'fid'=>$this->field->id, 'mode'=>'display', 'sesskey'=>sesskey());
- $link = new moodle_url('/mod/data/field.php', $params);
- $str = '<a href="'.$link->out().'">';
- $str .= $OUTPUT->pix_icon('field/' . $this->type, $this->type, 'data');
- $str .= '</a>';
- return $str;
- }
- /**
- * Per default, it is assumed that fields support text exporting.
- * Override this (return false) on fields not supporting text exporting.
- *
- * @return bool true
- */
- function text_export_supported() {
- return true;
- }
- /**
- * Per default, return the record's text value only from the "content" field.
- * Override this in fields class if necesarry.
- *
- * @param string $record
- * @return string
- */
- function export_text_value($record) {
- if ($this->text_export_supported()) {
- return $record->content;
- }
- }
- /**
- * @param string $relativepath
- * @return bool false
- */
- function file_ok($relativepath) {
- return false;
- }
- /**
- * Returns the priority for being indexed by globalsearch
- *
- * @return int
- */
- public static function get_priority() {
- return static::$priority;
- }
- /**
- * Returns the presentable string value for a field content.
- *
- * The returned string should be plain text.
- *
- * @param stdClass $content
- * @return string
- */
- public static function get_content_value($content) {
- return trim($content->content, "\r\n ");
- }
- /**
- * Return the plugin configs for external functions,
- * in some cases the configs will need formatting or be returned only if the current user has some capabilities enabled.
- *
- * @return array the list of config parameters
- * @since Moodle 3.3
- */
- public function get_config_for_external() {
- // Return all the field configs to null (maybe there is a private key for a service or something similar there).
- $configs = [];
- for ($i = 1; $i <= 10; $i++) {
- $configs["param$i"] = null;
- }
- return $configs;
- }
- }
- /**
- * Given a template and a dataid, generate a default case template
- *
- * @global object
- * @param object $data
- * @param string template [addtemplate, singletemplate, listtempalte, rsstemplate]
- * @param int $recordid
- * @param bool $form
- * @param bool $update
- * @return bool|string
- */
- function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
- global $DB;
- if (!$data && !$template) {
- return false;
- }
- if ($template == 'csstemplate' or $template == 'jstemplate' ) {
- return '';
- }
- // get all the fields for that database
- if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id), 'id')) {
- $table = new html_table();
- $table->attributes['class'] = 'mod-data-default-template ##approvalstatusclass##';
- $table->colclasses = array('template-field', 'template-token');
- $table->data = array();
- foreach ($fields as $field) {
- if ($form) { // Print forms instead of data
- $fieldobj = data_get_field($field, $data);
- $token = $fieldobj->display_add_field($recordid, null);
- } else { // Just print the tag
- $token = '[['.$field->name.']]';
- }
- $table->data[] = array(
- $field->name.': ',
- $token
- );
- }
- if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
- $label = new html_table_cell(get_string('tags') . ':');
- if ($form) {
- $cell = data_generate_tag_form();
- } else {
- $cell = new html_table_cell('##tags##');
- }
- $table->data[] = new html_table_row(array($label, $cell));
- }
- if ($template == 'listtemplate') {
- $cell = new html_table_cell('##edit## ##more## ##delete## ##approve## ##disapprove## ##export##');
- $cell->colspan = 2;
- $cell->attributes['class'] = 'controls';
- $table->data[] = new html_table_row(array($cell));
- } else if ($template == 'singletemplate') {
- $cell = new html_table_cell('##edit## ##delete## ##approve## ##disapprove## ##export##');
- $cell->colspan = 2;
- $cell->attributes['class'] = 'controls';
- $table->data[] = new html_table_row(array($cell));
- } else if ($template == 'asearchtemplate') {
- $row = new html_table_row(array(get_string('authorfirstname', 'data').': ', '##firstname##'));
- $row->attributes['class'] = 'searchcontrols';
- $table->data[] = $row;
- $row = new html_table_row(array(get_string('authorlastname', 'data').': ', '##lastname##'));
- $row->attributes['class'] = 'searchcontrols';
- $table->data[] = $row;
- }
- $str = '';
- if ($template == 'listtemplate'){
- $str .= '##delcheck##';
- $str .= html_writer::empty_tag('br');
- }
- $str .= html_writer::start_tag('div', array('class' => 'defaulttemplate'));
- $str .= html_writer::table($table);
- $str .= html_writer::end_tag('div');
- if ($template == 'listtemplate'){
- $str .= html_writer::empty_tag('hr');
- }
- if ($update) {
- $newdata = new stdClass();
- $newdata->id = $data->id;
- $newdata->{$template} = $str;
- $DB->update_record('data', $newdata);
- $data->{$template} = $str;
- }
- return $str;
- }
- }
- /**
- * Build the form elements to manage tags for a record.
- *
- * @param int|bool $recordid
- * @param string[] $selected raw tag names
- * @return string
- */
- function data_generate_tag_form($recordid = false, $selected = []) {
- global $CFG, $DB, $OUTPUT, $PAGE;
- $tagtypestoshow = \core_tag_area::get_showstandard('mod_data', 'data_records');
- $showstandard = ($tagtypestoshow != core_tag_tag::HIDE_STANDARD);
- $typenewtags = ($tagtypestoshow != core_tag_tag::STANDARD_ONLY);
- $str = html_writer::start_tag('div', array('class' => 'datatagcontrol'));
- $namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
- $tagcollid = \core_tag_area::get_collection('mod_data', 'data_records');
- $tags = [];
- $selectedtags = [];
- if ($showstandard) {
- $tags += $DB->get_records_menu('tag', array('isstandard' => 1, 'tagcollid' => $tagcollid),
- $namefield, 'id,' . $namefield . ' as fieldname');
- }
- if ($recordid) {
- $selectedtags += core_tag_tag::get_item_tags_array('mod_data', 'data_records', $recordid);
- }
- if (!empty($selected)) {
- list($sql, $params) = $DB->get_in_or_equal($selected, SQL_PARAMS_NAMED);
- $params['tagcollid'] = $tagcollid;
- $sql = "SELECT id, $namefield FROM {tag} WHERE tagcollid = :tagcollid AND rawname $sql";
- $selectedtags += $DB->get_records_sql_menu($sql, $params);
- }
- $tags += $selectedtags;
- $str .= '<select class="custom-select" name="tags[]" id="tags" multiple>';
- foreach ($tags as $tagid => $tag) {
- $selected = key_exists($tagid, $selectedtags) ? 'selected' : '';
- $str .= "<option value='$tag' $selected>$tag</option>";
- }
- $str .= '</select>';
- if (has_capability('moodle/tag:manage', context_system::instance()) && $showstandard) {
- $url = new moodle_url('/tag/manage.php', array('tc' => core_tag_area::get_collection('mod_data',
- 'data_records')));
- $str .= ' ' . $OUTPUT->action_link($url, get_string('managestandardtags', 'tag'));
- }
- $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array(
- '#tags',
- $typenewtags,
- '',
- get_string('entertags', 'tag'),
- false,
- $showstandard,
- get_string('noselection', 'form')
- )
- );
- $str .= html_writer::end_tag('div');
- return $str;
- }
- /**
- * Search for a field name and replaces it with another one in all the
- * form templates. Set $newfieldname as '' if you want to delete the
- * field from the form.
- *
- * @global object
- * @param object $data
- * @param string $searchfieldname
- * @param string $newfieldname
- * @return bool
- */
- function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
- global $DB;
- if (!empty($newfieldname)) {
- $prestring = '[[';
- $poststring = ']]';
- $idpart = '#id';
- } else {
- $prestring = '';
- $poststring = '';
- $idpart = '';
- }
- $newdata = new stdClass();
- $newdata->id = $data->id;
- $newdata->singletemplate = str_ireplace('[['.$searchfieldname.']]',
- $prestring.$newfieldname.$poststring, $data->singletemplate);
- $newdata->listtemplate = str_ireplace('[['.$searchfieldname.']]',
- $prestring.$newfieldname.$poststring, $data->listtemplate);
- $newdata->addtemplate = str_ireplace('[['.$searchfieldname.']]',
- $prestring.$newfieldname.$poststring, $data->addtemplate);
- $newdata->addtemplate = str_ireplace('[['.$searchfieldname.'#id]]',
- $prestring.$newfieldname.$idpart.$poststring, $data->addtemplate);
- $newdata->rsstemplate = str_ireplace('[['.$searchfieldname.']]',
- $prestring.$newfieldname.$poststring, $data->rsstemplate);
- return $DB->update_record('data', $newdata);
- }
- /**
- * Appends a new field at the end of the form template.
- *
- * @global object
- * @param object $data
- * @param string $newfieldname
- */
- function data_append_new_field_to_templates($data, $newfieldname) {
- global $DB;
- $newdata = new stdClass();
- $newdata->id = $data->id;
- $change = false;
- if (!empty($data->singletemplate)) {
- $newdata->singletemplate = $data->singletemplate.' [[' . $newfieldname .']]';
- $change = true;
- }
- if (!empty($data->addtemplate)) {
- $newdata->addtemplate = $data->addtemplate.' [[' . $newfieldname . ']]';
- $change = true;
- }
- if (!empty($data->rsstemplate)) {
- $newdata->rsstemplate = $data->singletemplate.' [[' . $newfieldname . ']]';
- $change = true;
- }
- if ($change) {
- $DB->update_record('data', $newdata);
- }
- }
- /**
- * given a field name
- * this function creates an instance of the particular subfield class
- *
- * @global object
- * @param string $name
- * @param object $data
- * @return object|bool
- */
- function data_get_field_from_name($name, $data){
- global $DB;
- $field = $DB->get_record('data_fields', array('name'=>$name, 'dataid'=>$data->id));
- if ($field) {
- return data_get_field($field, $data);
- } else {
- return false;
- }
- }
- /**
- * given a field id
- * this function creates an instance of the particular subfield class
- *
- * @global object
- * @param int $fieldid
- * @param object $data
- * @return bool|object
- */
- function data_get_field_from_id($fieldid, $data){
- global $DB;
- $field = $DB->get_record('data_fields', array('id'=>$fieldid, 'dataid'=>$data->id));
- if ($field) {
- return data_get_field($field, $data);
- } else {
- return false;
- }
- }
- /**
- * given a field id
- * this function creates an instance of the particular subfield class
- *
- * @global object
- * @param string $type
- * @param object $data
- * @return object
- */
- function data_get_field_new($type, $data) {
- global $CFG;
- require_once($CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php');
- $newfield = 'data_field_'.$type;
- $newfield = new $newfield(0, $data);
- return $newfield;
- }
- /**
- * returns a subclass field object given a record of the field, used to
- * invoke plugin methods
- * input: $param $field - record from db
- *
- * @global object
- * @param object $field
- * @param object $data
- * @param object $cm
- * @return object
- */
- function data_get_field($field, $data, $cm=null) {
- global $CFG;
- if ($field) {
- require_once('field/'.$field->type.'/field.class.php');
- $newfield = 'data_field_'.$field->type;
- $newfield = new $newfield($field, $data, $cm);
- return $newfield;
- }
- }
- /**
- * Given record object (or id), returns true if the record belongs to the current user
- *
- * @global object
- * @global object
- * @param mixed $record record object or id
- * @return bool
- */
- function data_isowner($record) {
- global $USER, $DB;
- if (!isloggedin()) { // perf shortcut
- return false;
- }
- if (!is_object($record)) {
- if (!$record = $DB->get_record('data_records', array('id'=>$record))) {
- return false;
- }
- }
- return ($record->userid == $USER->id);
- }
- /**
- * has a user reached the max number of entries?
- *
- * @param object $data
- * @return bool
- */
- function data_atmaxentries($data){
- if (!$data->maxentries){
- return false;
- } else {
- return (data_numentries($data) >= $data->maxentries);
- }
- }
- /**
- * returns the number of entries already made by this user
- *
- * @global object
- * @global object
- * @param object $data
- * @return int
- */
- function data_numentries($data, $userid=null) {
- global $USER, $DB;
- if ($userid === null) {
- $userid = $USER->id;
- }
- $sql = 'SELECT COUNT(*) FROM {data_records} WHERE dataid=? AND userid=?';
- return $DB->count_records_sql($sql, array($data->id, $userid));
- }
- /**
- * function that takes in a dataid and adds a record
- * this is used everytime an add template is submitted
- *
- * @global object
- * @global object
- * @param object $data
- * @param int $groupid
- * @param int $userid
- * @return bool
- */
- function data_add_record($data, $groupid = 0, $userid = null) {
- global $USER, $DB;
- $cm = get_coursemodule_from_instance('data', $data->id);
- $context = context_module::instance($cm->id);
- $record = new stdClass();
- $record->userid = $userid ?? $USER->id;
- $record->dataid = $data->id;
- $record->groupid = $groupid;
- $record->timecreated = $record->timemodified = time();
- if (has_capability('mod/data:approve', $context)) {
- $record->approved = 1;
- } else {
- $record->approved = 0;
- }
- $record->id = $DB->insert_record('data_records', $record);
- // Trigger an event for creating this record.
- $event = \mod_data\event\record_created::create(array(
- 'objectid' => $record->id,
- 'context' => $context,
- 'other' => array(
- 'dataid' => $data->id
- )
- ));
- $event->trigger();
- $course = get_course($cm->course);
- data_update_completion_state($data, $course, $cm);
- return $record->id;
- }
- /**
- * check the multple existence any tag in a template
- *
- * check to see if there are 2 or more of the same tag being used.
- *
- * @global object
- * @param int $dataid,
- * @param string $template
- * @return bool
- */
- function data_tags_check($dataid, $template) {
- global $DB, $OUTPUT;
- // first get all the possible tags
- $fields = $DB->get_records('data_fields', array('dataid'=>$dataid));
- // then we generate strings to replace
- $tagsok = true; // let's be optimistic
- foreach ($fields as $field){
- $pattern="/\[\[" . preg_quote($field->name, '/') . "\]\]/i";
- if (preg_match_all($pattern, $template, $dummy)>1){
- $tagsok = false;
- echo $OUTPUT->notification('[['.$field->name.']] - '.get_string('multipletags','data'));
- }
- }
- // else return true
- return $tagsok;
- }
- /**
- * Adds an instance of a data
- *
- * @param stdClass $data
- * @param mod_data_mod_form $mform
- * @return int intance id
- */
- function data_add_instance($data, $mform = null) {
- global $DB, $CFG;
- require_once($CFG->dirroot.'/mod/data/locallib.php');
- if (empty($data->assessed)) {
- $data->assessed = 0;
- }
- if (empty($data->ratingtime) || empty($data->assessed)) {
- $data->assesstimestart = 0;
- $data->assesstimefinish = 0;
- }
- $data->timemodified = time();
- $data->id = $DB->insert_record('data', $data);
- // Add calendar events if necessary.
- data_set_events($data);
- if (!empty($data->completionexpected)) {
- \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $data->completionexpected);
- }
- data_grade_item_update($data);
- return $data->id;
- }
- /**
- * updates an instance of a data
- *
- * @global object
- * @param object $data
- * @return bool
- */
- function data_update_instance($data) {
- global $DB, $CFG;
- require_once($CFG->dirroot.'/mod/data/locallib.php');
- $data->timemodified = time();
- $data->id = $data->instance;
- if (empty($data->assessed)) {
- $data->assessed = 0;
- }
- if (empty($data->ratingtime) or empty($data->assessed)) {
- $data->assesstimestart = 0;
- $data->assesstimefinish = 0;
- }
- if (empty($data->notification)) {
- $data->notification = 0;
- }
- $DB->update_record('data', $data);
- // Add calendar events if necessary.
- data_set_events($data);
- $completionexpected = (!empty($data->completionexpected)) ? $data->completionexpected : null;
- \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $completionexpected);
- data_grade_item_update($data);
- return true;
- }
- /**
- * deletes an instance of a data
- *
- * @global object
- * @param int $id
- * @return bool
- */
- function data_delete_instance($id) { // takes the dataid
- global $DB, $CFG;
- if (!$data = $DB->get_record('data', array('id'=>$id))) {
- return false;
- }
- $cm = get_coursemodule_from_instance('data', $data->id);
- $context = context_module::instance($cm->id);
- /// Delete all the associated information
- // files
- $fs = get_file_storage();
- $fs->delete_area_files($context->id, 'mod_data');
- // get all the records in this data
- $sql = "SELECT r.id
- FROM {data_records} r
- WHERE r.dataid = ?";
- $DB->delete_records_select('data_content', "recordid IN ($sql)", array($id));
- // delete all the records and fields
- $DB->delete_records('data_records', array('dataid'=>$id));
- $DB->delete_records('data_fields', array('dataid'=>$id));
- // Remove old calendar events.
- $events = $DB->get_records('event', array('modulename' => 'data', 'instance' => $id));
- foreach ($events as $event) {
- $event = calendar_event::load($event);
- $event->delete();
- }
- // cleanup gradebook
- data_grade_item_delete($data);
- // Delete the instance itself
- // We must delete the module record after we delete the grade item.
- $result = $DB->delete_records('data', array('id'=>$id));
- return $result;
- }
- /**
- * returns a summary of data activity of this user
- *
- * @global object
- * @param object $course
- * @param object $user
- * @param object $mod
- * @param object $data
- * @return object|null
- */
- function data_user_outline($course, $user, $mod, $data) {
- global $DB, $CFG;
- require_once("$CFG->libdir/gradelib.php");
- $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
- if (empty($grades->items[0]->grades)) {
- $grade = false;
- } else {
- $grade = reset($grades->items[0]->grades);
- }
- if ($countrecords = $DB->count_records('data_records', array('dataid'=>$data->id, 'userid'=>$user->id))) {
- $result = new stdClass();
- $result->info = get_string('numrecords', 'data', $countrecords);
- $lastrecord = $DB->get_record_sql('SELECT id,timemodified FROM {data_records}
- WHERE dataid = ? AND userid = ?
- ORDER BY timemodified DESC', array($data->id, $user->id), true);
- $result->time = $lastrecord->timemodified;
- if ($grade) {
- if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
- $result->info .= ', ' . get_string('gradenoun') . ': ' . $grade->str_long_grade;
- } else {
- $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
- }
- }
- return $result;
- } else if ($grade) {
- $result = (object) [
- 'time' => grade_get_date_for_user_grade($grade, $user),
- ];
- if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
- $result->info = get_string('gradenoun') . ': ' . $grade->str_long_grade;
- } else {
- $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
- }
- return $result;
- }
- return NULL;
- }
- /**
- * Prints all the records uploaded by this user
- *
- * @global object
- * @param object $course
- * @param object $user
- * @param object $mod
- * @param object $data
- */
- function data_user_complete($course, $user, $mod, $data) {
- global $DB, $CFG, $OUTPUT;
- require_once("$CFG->libdir/gradelib.php");
- $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
- if (!empty($grades->items[0]->grades)) {
- $grade = reset($grades->items[0]->grades);
- if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
- echo $OUTPUT->container(get_string('gradenoun') . ': ' . $grade->str_long_grade);
- if ($grade->str_feedback) {
- echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
- }
- } else {
- echo $OUTPUT->container(get_string('gradenoun') . ': ' . get_string('hidden', 'grades'));
- }
- }
- if ($records = $DB->get_records('data_records', array('dataid'=>$data->id,'userid'=>$user->id), 'timemodified DESC')) {
- data_print_template('singletemplate', $records, $data);
- }
- }
- /**
- * Return grade for given user or all users.
- *
- * @global object
- * @param object $data
- * @param int $userid optional user id, 0 means all users
- * @return array array of grades, false if none
- */
- function data_get_user_grades($data, $userid=0) {
- global $CFG;
- require_once($CFG->dirroot.'/rating/lib.php');
- $ratingoptions = new stdClass;
- $ratingoptions->component = 'mod_data';
- $ratingoptions->ratingarea = 'entry';
- $ratingoptions->modulename = 'data';
- $ratingoptions->moduleid = $data->id;
- $ratingoptions->userid = $userid;
- $ratingoptions->aggregationmethod = $data->assessed;
- $ratingoptions->scaleid = $data->scale;
- $ratingoptions->itemtable = 'data_records';
- $ratingoptions->itemtableusercolumn = 'userid';
- $rm = new rating_manager();
- return $rm->get_user_grades($ratingoptions);
- }
- /**
- * Update activity grades
- *
- * @category grade
- * @param object $data
- * @param int $userid specific user only, 0 means all
- * @param bool $nullifnone
- */
- function data_update_grades($data, $userid=0, $nullifnone=true) {
- global $CFG, $DB;
- require_once($CFG->libdir.'/gradelib.php');
- if (!$data->assessed) {
- data_grade_item_update($data);
- } else if ($grades = data_get_user_grades($data, $userid)) {
- data_grade_item_update($data, $grades);
- } else if ($userid and $nullifnone) {
- $grade = new stdClass();
- $grade->userid = $userid;
- $grade->rawgrade = NULL;
- data_grade_item_update($data, $grade);
- } else {
- data_grade_item_update($data);
- }
- }
- /**
- * Update/create grade item for given data
- *
- * @category grade
- * @param stdClass $data A database instance with extra cmidnumber property
- * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
- * @return object grade_item
- */
- function data_grade_item_update($data, $grades=NULL) {
- global $CFG;
- require_once($CFG->libdir.'/gradelib.php');
- $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
- if (!$data->assessed or $data->scale == 0) {
- $params['gradetype'] = GRADE_TYPE_NONE;
- } else if ($data->scale > 0) {
- $params['gradetype'] = GRADE_TYPE_VALUE;
- $params['grademax'] = $data->scale;
- $params['grademin'] = 0;
- } else if ($data->scale < 0) {
- $params['gradetype'] = GRADE_TYPE_SCALE;
- $params['scaleid'] = -$data->scale;
- }
- if ($grades === 'reset') {
- $params['reset'] = true;
- $grades = NULL;
- }
- return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades, $params);
- }
- /**
- * Delete grade item for given data
- *
- * @category grade
- * @param object $data object
- * @return object grade_item
- */
- function data_grade_item_delete($data) {
- global $CFG;
- require_once($CFG->libdir.'/gradelib.php');
- return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
- }
- // junk functions
- /**
- * takes a list of records, the current data, a search string,
- * and mode to display prints the translated template
- *
- * @global object
- * @global object
- * @param string $template
- * @param array $records
- * @param object $data
- * @param string $search
- * @param int $page
- * @param bool $return
- * @param object $jumpurl a moodle_url by which to jump back to the record list (can be null)
- * @return mixed
- */
- function data_print_template($template, $records, $data, $search='', $page=0, $return=false, moodle_url $jumpurl=null) {
- global $CFG, $DB, $OUTPUT;
- $cm = get_coursemodule_from_instance('data', $data->id);
- $context = context_module::instance($cm->id);
- static $fields = array();
- static $dataid = null;
- if (empty($dataid)) {
- $dataid = $data->id;
- } else if ($dataid != $data->id) {
- $fields = array();
- }
- if (empty($fields)) {
- $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$data->id));
- foreach ($fieldrecords as $fieldrecord) {
- $fields[]= data_get_field($fieldrecord, $data);
- }
- }
- if (empty($records)) {
- return;
- }
- if (!$jumpurl) {
- $jumpurl = new moodle_url('/mod/data/view.php', array('d' => $data->id));
- }
- $jumpurl = new moodle_url($jumpurl, array('page' => $page, 'sesskey' => sesskey()));
- foreach ($records as $record) { // Might be just one for the single template
- // Replacing tags
- $patterns = array();
- $replacement = array();
- // Then we generate strings to replace for normal tags
- foreach ($fields as $field) {
- $patterns[]='[['.$field->field->name.']]';
- $replacement[] = highlight($search, $field->display_browse_field($record->id, $template));
- }
- $canmanageentries = has_capability('mod/data:manageentries', $context);
- // Replacing special tags (##Edit##, ##Delete##, ##More##)
- $patterns[]='##edit##';
- $patterns[]='##delete##';
- if (data_user_can_manage_entry($record, $data, $context)) {
- $backtourlparams = [
- 'd' => $data->id,
- ];
- if ($template === 'singletemplate') {
- $backtourlparams['mode'] = 'single';
- }
- $backtourl = new \moodle_url('/mod/data/view.php', $backtourlparams);
- $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
- .$data->id.'&rid='.$record->id.'&sesskey='.sesskey().'&backto='
- . urlencode($backtourl->out(false)) .'">' .
- $OUTPUT->pix_icon('t/edit', get_string('edit')) . '</a>';
- $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
- .$data->id.'&delete='.$record->id.'&sesskey='.sesskey().'">' .
- $OUTPUT->pix_icon('t/delete', get_string('delete')) . '</a>';
- } else {
- $replacement[] = '';
- $replacement[] = '';
- }
- $moreurl = $CFG->wwwroot . '/mod/data/view.php?d=' . $data->id . '&rid=' . $record->id;
- if ($search) {
- $moreurl .= '&filter=1';
- }
- $patterns[]='##more##';
- $replacement[] = '<a href="'.$moreurl.'">' . $OUTPUT->pix_icon('t/preview', get_string('more', 'data')) . '</a>';
- $patterns[]='##moreurl##';
- $replacement[] = $moreurl;
- $patterns[]='##delcheck##';
- if ($canmanageentries) {
- $checkbox = new \core\output\checkbox_toggleall('listview-entries', false, [
- 'id' => "entry_{$record->id}",
- 'name' => 'delcheck[]',
- 'classes' => 'recordcheckbox',
- 'value' => $record->id,
- ]);
- $replacement[] = $OUTPUT->render($checkbox);
- } else {
- $replacement[] = '';
- }
- $patterns[]='##user##';
- $replacement[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$record->userid.
- '&course='.$data->course.'">'.fullname($record).'</a>';
- $patterns[] = '##userpicture##';
- $ruser = user_picture::unalias($record, null, 'userid');
- // If the record didn't come with user data, retrieve the user from database.
- if (!isset($ruser->picture)) {
- $ruser = core_user::get_user($record->userid);
- }
- $replacement[] = $OUTPUT->user_picture($ruser, array('courseid' => $data->course));
- $patterns[]='##export##';
- if (!empty($CFG->enableportfolios) && ($template == 'singletemplate' || $template == 'listtemplate')
- && ((has_capability('mod/data:exportentry', $context)
- || (data_isowner($record->id) && has_capability('mod/data:exportownentry', $context))))) {
- require_once($CFG->libdir . '/portfoliolib.php');
- $button = new portfolio_add_button();
- $button->set_callback_options('data_portfolio_caller', array('id' => $cm->id, 'recordid' => $record->id), 'mod_data');
- list($formats, $files) = data_portfolio_caller::formats($fields, $record);
- $button->set_formats($formats);
- $replacement[] = $button->to_html(PORTFOLIO_ADD_ICON_LINK);
- } else {
- $replacement[] = '';
- }
- $patterns[] = '##timeadded##';
- $replacement[] = userdate($record->timecreated);
- $patterns[] = '##timemodified##';
- $replacement [] = userdate($record->timemodified);
- $patterns[]='##approve##';
- if (has_capability('mod/data:approve', $context) && ($data->approval) && (!$record->approved)) {
- $approveurl = new moodle_url($jumpurl, array('approve' => $record->id));
- $approveicon = new pix_icon('t/approve', get_string('approve', 'data'), '', array('class' => 'iconsmall'));
- $replacement[] = html_writer::tag('span', $OUTPUT->action_icon($approveurl, $approveicon),
- array('class' => 'approve'));
- } else {
- $replacement[] = '';
- }
- $patterns[]='##disapprove##';
- if (has_capability('mod/data:approve', $context) && ($data->approval) && ($record->approved)) {
- $disapproveurl = new moodle_url($jumpurl, array('disapprove' => $record->id));
- $disapproveicon = new pix_icon('t/block', get_string('disapprove', 'data'), '', array('class' => 'iconsmall'));
- $replacement[] = html_writer::tag('span', $OUTPUT->action_icon($disapproveurl, $disapproveicon),
- array('class' => 'disapprove'));
- } else {
- $replacement[] = '';
- }
- $patterns[] = '##approvalstatus##';
- $patterns[] = '##approvalstatusclass##';
- if (!$data->approval) {
- $replacement[] = '';
- $replacement[] = '';
- } else if ($record->approved) {
- $replacement[] = get_string('approved', 'data');
- $replacement[] = 'approved';
- } else {
- $replacement[] = get_string('notapproved', 'data');
- $replacement[] = 'notapproved';
- }
- $patterns[]='##comments##';
- if (($template == 'listtemplate') && ($data->comments)) {
- if (!empty($CFG->usecomments)) {
- require_once($CFG->dirroot . '/comment/lib.php');
- list($context, $course, $cm) = get_context_info_array($context->id);
- $cmt = new stdClass();
- $cmt->context = $context;
- $cmt->course = $course;
- $cmt->cm = $cm;
- $cmt->area = 'database_entry';
- $cmt->itemid = $record->id;
- $cmt->showcount = true;
- $cmt->component = 'mod_data';
- $comment = new comment($cmt);
- $replacement[] = $comment->output(true);
- }
- } else {
- $replacement[] = '';
- }
- if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
- $patterns[] = "##tags##";
- $replacement[] = $OUTPUT->tag_list(
- core_tag_tag::get_item_tags('mod_data', 'data_records', $record->id), '', 'data-tags');
- }
- // actual replacement of the tags
- $newtext = str_ireplace($patterns, $replacement, $data->{$template});
- // no more html formatting and filtering - see MDL-6635
- if ($return) {
- return $newtext;
- } else {
- echo $newtext;
- // hack alert - retu…
Large files files are truncated, but you can click here to view the full file