MDL-75146 mod_data: refactor template parser

This commit is contained in:
Ferran Recio 2022-07-08 18:07:38 +02:00 committed by Sara Arjona
parent e2da14bbb8
commit 776e48748f
8 changed files with 1357 additions and 266 deletions

View File

@ -407,6 +407,8 @@ class mod_data_external extends external_api {
}
}
$manager = manager::create_from_instance($database);
list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
data_search_entries($database, $cm, $context, 'list', $groupid, '', $params['sort'], $params['order'],
$params['page'], $params['perpage']);
@ -449,11 +451,8 @@ class mod_data_external extends external_api {
// Check if we should return the list rendered.
if ($params['returncontents']) {
ob_start();
// The return parameter stops the execution after the first record.
data_print_template('listtemplate', $records, $database, '', $page, false);
$result['listviewcontents'] = ob_get_contents();
ob_end_clean();
$parser = $manager->get_template('listtemplate', ['page' => $page]);
$result['listviewcontents'] = $parser->parse_entries($records);
}
return $result;
@ -518,6 +517,8 @@ class mod_data_external extends external_api {
$canmanageentries = has_capability('mod/data:manageentries', $context);
data_require_time_available($database, $canmanageentries);
$manager = manager::create_from_instance($database);
if ($record->groupid != 0) {
if (!groups_group_visible($record->groupid, $course, $cm)) {
throw new moodle_exception('notingroup');
@ -546,7 +547,8 @@ class mod_data_external extends external_api {
// Check if we should return the entry rendered.
if ($params['returncontents']) {
$records = [$record];
$result['entryviewcontents'] = data_print_template('singletemplate', $records, $database, '', 0, true);
$parser = $manager->get_template('singletemplate');
$result['entryviewcontents'] = $parser->parse_entries($records);
}
return $result;
@ -717,6 +719,8 @@ class mod_data_external extends external_api {
// Check database is open in time.
data_require_time_available($database, null, $context);
$manager = manager::create_from_instance($database);
if (!empty($params['groupid'])) {
$groupid = $params['groupid'];
// Determine is the group is visible to user.
@ -782,11 +786,8 @@ class mod_data_external extends external_api {
// Check if we should return the list rendered.
if ($params['returncontents']) {
ob_start();
// The return parameter stops the execution after the first record.
data_print_template('listtemplate', $records, $database, '', $page, false);
$result['listviewcontents'] = ob_get_contents();
ob_end_clean();
$parser = $manager->get_template('listtemplate', ['page' => $page]);
$result['listviewcontents'] = $parser->parse_entries($records);
}
return $result;

View File

@ -253,16 +253,16 @@ class manager {
$templatename == 'singletemplate';
}
$instance = $this->instance;
$templatestr = $instance->{$templatename} ?? '';
if (empty($templatestr)) {
$templatestr = data_generate_default_template($instance, $templatename, 0, false, false);
$templatecontent = $instance->{$templatename} ?? '';
if (empty($templatecontent)) {
$templatecontent = data_generate_default_template($instance, $templatename, 0, false, false);
}
// Some templates have extra options.
if ($templatename == 'singletemplate') {
$options['comments'] = true;
$options['ratings'] = true;
}
return new template($this, $templatestr, $options);
return new template($this, $templatecontent, $options);
}
/**

View File

@ -0,0 +1,598 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_data;
use core\output\checkbox_toggleall;
use html_writer;
use mod_data\manager;
use moodle_url;
use pix_icon;
use stdClass;
use user_picture;
use core_user;
use portfolio_add_button;
use data_portfolio_caller;
use comment;
use core_tag_tag;
/**
* Class template for database activity
*
* @package mod_data
* @copyright 2022 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class template {
/** @var manager the current instance manager. */
private $manager;
/** @var stdClass the current instance record. */
private $instance;
/** @var string the template. */
private $templatecontent;
/** @var moodle_url the base url. */
private $baseurl;
/** @var string the current search if any. */
private $search;
/** @var bool if ratings must be added. */
private $ratings;
/** @var bool if comments must be added if not present in the template. */
private $forcecomments;
/** @var bool if the current user can manage entries. */
private $canmanageentries = null;
/** @var array if icons HTML. */
private $icons = [];
/** @var array All template tags (calculated in load_template_tags). */
protected $tags = [];
/**
* Class contructor.
*
* See the add_options method for the available display options.
*
* @param manager $manager the current instance manager
* @param string $templatecontent the template string to use
* @param array $options an array of extra diplay options
*/
public function __construct(manager $manager, string $templatecontent, array $options = []) {
$this->manager = $manager;
$this->instance = $manager->get_instance();
$this->templatecontent = $templatecontent;
$context = $manager->get_context();
$this->canmanageentries = has_capability('mod/data:manageentries', $context);
$this->icons = $this->get_icons();
$this->add_options($options);
$this->load_template_tags($templatecontent);
}
/**
* Add extra display options.
*
* The extra options are:
* - page: the current pagination page
* - search: the current search text
* - baseurl: an alternative entry url (moodle_url)
* - comments: if comments must be added if not present
* - ratings: if ratings must be added
*
* @param array $options the array of options.
*/
public function add_options(array $options = []) {
$cm = $this->manager->get_coursemodule();
$baseurl = $options['baseurl'] ?? new moodle_url('/mod/data/view.php', ['id' => $cm->id]);
if (isset($options['page'])) {
$baseurl->params([
'page' => $options['page'],
]);
}
$this->baseurl = $baseurl;
// Save options.
$this->search = $options['search'] ?? null;
$this->ratings = $options['ratings'] ?? false;
$this->forcecomments = $options['comments'] ?? false;
}
/**
* Scan the template tags.
*
* This method detects which tags are used in this template and store them
* in the $this->tags attribute. This attribute will be used to determine
* which replacements needs to be calculated.
*
* @param string $templatecontent the current template
*/
protected function load_template_tags(string $templatecontent) {
// Detect action tags.
$pattern = '/##(?P<tags>\w+?)##/';
$matches = [];
preg_match_all($pattern, $templatecontent, $matches);
if (!isset($matches['tags']) || empty($matches['tags'])) {
return;
}
$this->tags = $matches['tags'];
}
/**
* Generate the list of action icons.
*
* @return pix_icon[] icon name => pix_icon
*/
protected function get_icons() {
$attrs = ['class' => 'iconsmall'];
return [
'edit' => new pix_icon('t/edit', get_string('edit'), '', $attrs),
'delete' => new pix_icon('t/delete', get_string('delete'), '', $attrs),
'more' => new pix_icon('t/preview', get_string('more', 'data'), '', $attrs),
'approve' => new pix_icon('t/approve', get_string('approve', 'data'), '', $attrs),
'disapprove' => new pix_icon('t/block', get_string('disapprove', 'data'), '', $attrs),
];
}
/**
* Return the parsed entry using a template.
*
* This method apply a template replacing all necessary tags.
*
* @param array $entries of entres to parse
* @return string the entries outputs using the template
*/
public function parse_entries(array $entries): string {
if (empty($entries)) {
return '';
}
$result = '';
foreach ($entries as $entry) {
$result .= $this->parse_entry($entry);
}
return $result;
}
/**
* Parse a single entry.
*
* @param stdClass $entry the entry to parse
* @return string the parsed entry
*/
private function parse_entry(stdClass $entry): string {
if (empty($this->templatecontent)) {
return '';
}
$context = $this->manager->get_context();
$canmanageentry = data_user_can_manage_entry($entry, $this->instance, $context);
// Load all replacements for the entry.
$fields = $this->get_fields_replacements($entry);
$tags = $this->get_tags_replacements($entry, $canmanageentry);
$replacements = array_merge($fields, $tags);
$patterns = array_keys($replacements);
$replacement = array_values($replacements);
$result = str_ireplace($patterns, $replacement, $this->templatecontent);
return $this->post_parse($result, $entry);
}
/**
* Get all field replacements.
*
* @param stdClass $entry the entry object
* @return array of pattern => replacement
*/
private function get_fields_replacements(stdClass $entry): array {
$result = [];
$fields = $this->manager->get_fields();
foreach ($fields as $field) {
// Field value.
$pattern = '[[' . $field->field->name . ']]';
$result[$pattern] = highlight(
$this->search,
$field->display_browse_field($entry->id, $this->templatecontent)
);
// Field id.
$pattern = '[[' . $field->field->name . '#id]]';
$result[$pattern] = $field->field->id;
}
return $result;
}
/**
* Get all standard tags replacements.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return array of pattern => replacement
*/
private function get_tags_replacements(stdClass $entry, bool $canmanageentry): array {
$result = [];
foreach ($this->tags as $tagname) {
$methodname = "get_tag_{$tagname}_replacement";
if (method_exists($this, $methodname)) {
$pattern = "##$tagname##";
$replacement = $this->$methodname($entry, $canmanageentry);
$result[$pattern] = $replacement;
}
}
return $result;
}
/**
* Add any extra information to the parsed entry.
*
* @param string $result the parsed template with the entry data
* @param stdClass $entry the entry object
* @return string the final parsed template
*/
private function post_parse(string $result, stdClass $entry): string {
if ($this->ratings) {
$result .= data_print_ratings($this->instance, $entry, false);
}
if ($this->forcecomments && strpos($this->templatecontent, '##comments##') === false) {
$result .= $this->get_tag_comments_replacement($entry, false);
}
return $result;
}
/**
* Returns the ##edit## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_edit_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
if (!$canmanageentry) {
return '';
}
$backurl = new moodle_url($this->baseurl, [
'rid' => $entry->id,
'mode' => 'single',
]);
$url = new moodle_url('/mod/data/edit.php', $this->baseurl->params());
$url->params([
'rid' => $entry->id,
'sesskey' => sesskey(),
'backto' => urlencode($backurl->out(false))
]);
return html_writer::tag(
'span',
$OUTPUT->action_icon($url, $this->icons['edit']),
['class' => 'edit']
);
}
/**
* Returns the ##delete## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_delete_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
if (!$canmanageentry) {
return '';
}
$url = new moodle_url($this->baseurl, [
'delete' => $entry->id,
'sesskey' => sesskey(),
'mode' => 'single',
]);
return html_writer::tag(
'span',
$OUTPUT->action_icon($url, $this->icons['delete']),
['class' => 'delete']
);
}
/**
* Returns the ##more## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_more_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
$url = new moodle_url($this->baseurl, [
'rid' => $entry->id,
'filter' => 1,
]);
return html_writer::tag(
'span',
$OUTPUT->action_icon($url, $this->icons['more']),
['class' => 'more']
);
}
/**
* Returns the ##moreurl## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_moreurl_replacement(stdClass $entry, bool $canmanageentry): string {
$url = new moodle_url($this->baseurl, [
'rid' => $entry->id,
'filter' => 1,
]);
return $url->out(false);
}
/**
* Returns the ##delcheck## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_delcheck_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
if (!$this->canmanageentries) {
return '';
}
$checkbox = new checkbox_toggleall('listview-entries', false, [
'id' => "entry_{$entry->id}",
'name' => 'delcheck[]',
'classes' => 'recordcheckbox',
'value' => $entry->id,
]);
return $OUTPUT->render($checkbox);
}
/**
* Returns the ##user## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_user_replacement(stdClass $entry, bool $canmanageentry): string {
$cm = $this->manager->get_coursemodule();
$url = new moodle_url('/user/view.php', [
'id' => $entry->userid,
'course' => $cm->course,
]);
return html_writer::tag(
'a',
fullname($entry),
['href' => $url->out(false)]
);
}
/**
* Returns the ##userpicture## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_userpicture_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
$cm = $this->manager->get_coursemodule();
$user = user_picture::unalias($entry, null, 'userid');
// If the record didn't come with user data, retrieve the user from database.
if (!isset($user->picture)) {
$user = core_user::get_user($entry->userid);
}
return $OUTPUT->user_picture($user, ['courseid' => $cm->course]);
}
/**
* Returns the ##export## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_export_replacement(stdClass $entry, bool $canmanageentry): string {
global $CFG;
if (empty($CFG->enableportfolios)) {
return '';
}
// Check the user can export the entry.
$cm = $this->manager->get_coursemodule();
$context = $this->manager->get_context();
$canexportall = has_capability('mod/data:exportentry', $context);
$canexportown = has_capability('mod/data:exportownentry', $context);
if (!$canexportall && !(data_isowner($entry->id) && $canexportown)) {
return '';
}
// Add the portfolio export button.
require_once($CFG->libdir . '/portfoliolib.php');
$button = new portfolio_add_button();
$button->set_callback_options(
'data_portfolio_caller',
['id' => $cm->id, 'recordid' => $entry->id],
'mod_data'
);
$fields = $this->manager->get_fields();
list($formats, $files) = data_portfolio_caller::formats($fields, $entry);
$button->set_formats($formats);
return $button->to_html(PORTFOLIO_ADD_ICON_LINK);
}
/**
* Returns the ##timeadded## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_timeadded_replacement(stdClass $entry, bool $canmanageentry): string {
return userdate($entry->timecreated);
}
/**
* Returns the ##timemodified## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_timemodified_replacement(stdClass $entry, bool $canmanageentry): string {
return userdate($entry->timemodified);
}
/**
* Returns the ##approve## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_approve_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
$context = $this->manager->get_context();
if (!has_capability('mod/data:approve', $context) || !$this->instance->approval || $entry->approved) {
return '';
}
$url = new moodle_url($this->baseurl, [
'approve' => $entry->id,
'sesskey' => sesskey(),
]);
return html_writer::tag(
'span',
$OUTPUT->action_icon($url, $this->icons['approve']),
['class' => 'approve']
);
}
/**
* Returns the ##disapprove## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_disapprove_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
$context = $this->manager->get_context();
if (!has_capability('mod/data:approve', $context) || !$this->instance->approval || !$entry->approved) {
return '';
}
$url = new moodle_url($this->baseurl, [
'disapprove' => $entry->id,
'sesskey' => sesskey(),
]);
return html_writer::tag(
'span',
$OUTPUT->action_icon($url, $this->icons['disapprove']),
['class' => 'disapprove']
);
}
/**
* Returns the ##approvalstatus## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_approvalstatus_replacement(stdClass $entry, bool $canmanageentry): string {
if (!$this->instance->approval) {
return '';
}
return ($entry->approved) ? get_string('approved', 'data') : get_string('notapproved', 'data');
}
/**
* Returns the ##approvalstatusclass## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_approvalstatusclass_replacement(stdClass $entry, bool $canmanageentry): string {
if (!$this->instance->approval) {
return '';
}
return ($entry->approved) ? 'approved' : 'notapproved';
}
/**
* Returns the ##comments## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_comments_replacement(stdClass $entry, bool $canmanageentry): string {
global $CFG;
if (empty($CFG->usecomments) || empty($this->instance->comments)) {
return '';
}
$context = $this->manager->get_context();
require_once($CFG->dirroot . '/comment/lib.php');
list($context, $course, $cm) = get_context_info_array($context->id);
$cmdata = (object)[
'context' => $context,
'course' => $course,
'cm' => $cm,
'area' => 'database_entry',
'itemid' => $entry->id,
'showcount' => true,
'component' => 'mod_data',
];
$comment = new comment($cmdata);
return $comment->output(true);
}
/**
* Returns the ##tags## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_tags_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
if (!core_tag_tag::is_enabled('mod_data', 'data_records')) {
return '';
}
return $OUTPUT->tag_list(
core_tag_tag::get_item_tags('mod_data', 'data_records', $entry->id),
'',
'data-tags'
);
}
/**
* Returns the ##id## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_id_replacement(stdClass $entry, bool $canmanageentry): string {
return (string) $entry->id;
}
}

View File

@ -600,21 +600,25 @@ class data_field_base { // Base class for Database Field Types (see field/*/
/**
* 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
* @param stdClass $data the mod_data record.
* @param string $template the template name
* @param int $recordid the entry record
* @param bool $form print a form instead of data
* @param bool $update if the function update the $data object or not
* @return bool|string the template content.
*/
function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
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' ) {
if ($template == 'csstemplate'
|| $template == 'jstemplate'
|| $template == 'listtemplateheader'
|| $template == 'listtemplatefooter'
|| $template == 'rsstitletemplate'
) {
return '';
}
@ -1255,9 +1259,15 @@ function data_user_complete($course, $user, $mod, $data) {
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);
$records = $DB->get_records(
'data_records',
['dataid' => $data->id, 'userid' => $user->id],
'timemodified DESC'
);
if ($records) {
$manager = manager::create_from_instance($data);
$parser = $manager->get_template('singletemplate');
echo $parser->parse_entries($records);
}
}
@ -1373,239 +1383,37 @@ function data_grade_item_delete($data) {
* 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
* @deprecated since Moodle 4.1 MDL-75146 - please do not use this function any more.
* @todo MDL-75189 Final deprecation in Moodle 4.5.
* @param string $templatename the template name
* @param array $records the entries records
* @param stdClass $data the database instance object
* @param string $search the current search term
* @param int $page page number for pagination
* @param bool $return if the result should be returned (true) or printed (false)
* @param moodle_url|null $jumpurl a moodle_url by which to jump back to the record list (can be null)
* @return mixed string with all parsed entries or nothing if $return is false
*/
function data_print_template($template, $records, $data, $search='', $page=0, $return=false, moodle_url $jumpurl=null) {
global $CFG, $DB, $OUTPUT;
function data_print_template($templatename, $records, $data, $search='', $page=0, $return=false, moodle_url $jumpurl=null) {
debugging(
'data_print_template is deprecated. Use mod_data\\manager::get_template and mod_data\\template::parse_entries instead',
DEBUG_DEVELOPER
);
$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();
$options = [
'search' => $search,
'page' => $page,
];
if ($jumpurl) {
$options['baseurl'] = $jumpurl;
}
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.'&amp;rid='.$record->id.'&amp;sesskey='.sesskey().'&amp;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.'&amp;delete='.$record->id.'&amp;sesskey='.sesskey().'">' .
$OUTPUT->pix_icon('t/delete', get_string('delete')) . '</a>';
} else {
$replacement[] = '';
$replacement[] = '';
}
$moreurl = $CFG->wwwroot . '/mod/data/view.php?d=' . $data->id . '&amp;rid=' . $record->id;
if ($search) {
$moreurl .= '&amp;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.
'&amp;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 - return is always false in singletemplate anyway ;-)
/**********************************
* Printing Ratings Form *
*********************************/
if ($template == 'singletemplate') { //prints ratings options
data_print_ratings($data, $record);
}
/**********************************
* Printing Comments Form *
*********************************/
if (($template == 'singletemplate') && ($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);
$comment->output(false);
}
}
}
$manager = manager::create_from_instance($data);
$parser = $manager->get_template($templatename, $options);
$content = $parser->parse_entries($records);
if ($return) {
return $content;
}
echo $content;
}
/**
@ -1981,13 +1789,19 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
* @global object
* @param object $data
* @param object $record
* @param bool $print if the result must be printed or returner.
* @return void Output echo'd
*/
function data_print_ratings($data, $record) {
function data_print_ratings($data, $record, bool $print = true) {
global $OUTPUT;
$result = '';
if (!empty($record->rating)){
echo $OUTPUT->render($record->rating);
$result = $OUTPUT->render($record->rating);
}
if (!$print) {
return $result;
}
echo $result;
}
/**

View File

@ -25,6 +25,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use mod_data\manager;
defined('MOODLE_INTERNAL') || die();
/**
@ -59,6 +61,8 @@ defined('MOODLE_INTERNAL') || die();
return null;
}
$manager = manager::create_from_instance($data);
$sql = data_rss_get_sql($data);
//get the cache file info
@ -93,16 +97,18 @@ defined('MOODLE_INTERNAL') || die();
$recordarray = array();
array_push($recordarray, $record);
$item = null;
$item = new stdClass();
// guess title or not
if (!empty($data->rsstitletemplate)) {
$item->title = data_print_template('rsstitletemplate', $recordarray, $data, '', 0, true);
$parser = $manager->get_template('rsstitletemplate');
$item->title = $parser->parse_entries($recordarray);
} else { // else we guess
$item->title = strip_tags($DB->get_field('data_content', 'content',
array('fieldid'=>$firstfield->id, 'recordid'=>$record->id)));
}
$item->description = data_print_template('rsstemplate', $recordarray, $data, '', 0, true);
$parser = $manager->get_template('rsstemplate');
$item->title = $parser->parse_entries($recordarray);
$item->pubdate = $record->timecreated;
$item->link = $CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&rid='.$record->id;
@ -190,4 +196,3 @@ defined('MOODLE_INTERNAL') || die();
rss_delete_file('mod_data', $data);
}

View File

@ -0,0 +1,656 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_data;
use context_module;
use rating_manager;
use stdClass;
/**
* Template tests class for mod_data.
*
* @package mod_data
* @category test
* @copyright 2022 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_data\template
*/
class template_test extends \advanced_testcase {
/**
* Setup to ensure that fixtures are loaded.
*/
public static function setupBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/rating/lib.php');
}
/**
* Test for static create methods.
*
* @covers ::parse_entries
* @dataProvider parse_entries_provider
* @param string $templatecontent the template string
* @param string $expected expected output
* @param string $rolename the user rolename
* @param bool $enableexport is portfolio export is enabled
* @param bool $approved if the entry is approved
* @param bool $enablecomments is comments are enabled
* @param bool $enableratings if ratings are enabled
* @param array $options extra parser options
* @param bool $otherauthor if the entry is from another user
*/
public function test_parse_entries(
string $templatecontent,
string $expected,
string $rolename = 'editingteacher',
bool $enableexport = false,
bool $approved = true,
bool $enablecomments = false,
bool $enableratings = false,
array $options = [],
bool $otherauthor = false
) {
global $DB, $PAGE;
// Comments, tags, approval, user role.
$this->resetAfterTest();
$params = ['approval' => true];
// Enable comments.
if ($enablecomments) {
set_config('usecomments', 1);
$params['comments'] = true;
$PAGE->reset_theme_and_output();
$PAGE->set_url('/mod/data/view.php');
}
$course = $this->getDataGenerator()->create_course();
$params['course'] = $course;
$activity = $this->getDataGenerator()->create_module('data', $params);
$cm = get_coursemodule_from_id('data', $activity->cmid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$user = $this->getDataGenerator()->create_user();
$roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
$this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids[$rolename]);
$author = $user;
if ($otherauthor) {
$user2 = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleids[$rolename]);
$author = $user2;
}
// Generate an entry.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$fieldrecord = (object)[
'name' => 'myfield',
'type' => 'text',
];
$field = $generator->create_field($fieldrecord, $activity);
$this->setUser($user);
$entryid = $generator->create_entry(
$activity,
[$field->field->id => 'Example entry'],
0,
['Cats', 'Dogs'],
['approved' => $approved]
);
if ($enableexport) {
$this->enable_portfolio($user);
}
$manager = manager::create_from_instance($activity);
$entry = (object)[
'id' => $entryid,
'approved' => $approved,
'timecreated' => 1657618639,
'timemodified' => 1657618650,
'userid' => $author->id,
'groupid' => 0,
'dataid' => $activity->id,
'picture' => 0,
'firstname' => $author->firstname,
'lastname' => $author->lastname,
'firstnamephonetic' => $author->firstnamephonetic,
'lastnamephonetic' => $author->lastnamephonetic,
'middlename' => $author->middlename,
'alternatename' => $author->alternatename,
'imagealt' => 'PIXEXAMPLE',
'email' => $author->email,
];
$entries = [$entry];
if ($enableratings) {
$entries = $this->enable_ratings($context, $activity, $entries, $user);
}
// Some cooked variables for the regular expression.
$userfullname = fullname($user);
$timeadded = userdate($entry->timecreated);
$timemodified = userdate($entry->timemodified);
$fieldid = $field->field->id;
$replace = [
'{authorfullname}' => fullname($author),
'{timeadded}' => userdate($entry->timecreated),
'{timemodified}' => userdate($entry->timemodified),
'{fieldid}' => $field->field->id,
'{entryid}' => $entry->id,
'{cmid}' => $cm->id,
'{courseid}' => $course->id,
'{authorid}' => $author->id
];
$parser = new template($manager, $templatecontent, $options);
$result = $parser->parse_entries($entries);
// We don't want line breaks for the validations.
$result = str_replace("\n", '', $result);
$regexp = str_replace(array_keys($replace), array_values($replace), $expected);
$this->assertMatchesRegularExpression($regexp, $result);
}
/**
* Data provider for test_parse_entries().
*
* @return array of scenarios
*/
public function parse_entries_provider(): array {
return [
// Teacher scenarios.
'Teacher id tag' => [
'templatecontent' => 'Some ##id## tag',
'expected' => '|Some {entryid} tag|',
'rolename' => 'editingteacher',
],
'Teacher delete tag' => [
'templatecontent' => 'Some ##delete## tag',
'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
'rolename' => 'editingteacher',
],
'Teacher edit tag' => [
'templatecontent' => 'Some ##edit## tag',
'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
'rolename' => 'editingteacher',
],
'Teacher more tag' => [
'templatecontent' => 'Some ##more## tag',
'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
'rolename' => 'editingteacher',
],
'Teacher moreurl tag' => [
'templatecontent' => 'Some ##moreurl## tag',
'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
'rolename' => 'editingteacher',
],
'Teacher delcheck tag' => [
'templatecontent' => 'Some ##delcheck## tag',
'expected' => '|Some .*input.*checkbox.*value.*{entryid}.* tag|',
'rolename' => 'editingteacher',
],
'Teacher user tag' => [
'templatecontent' => 'Some ##user## tag',
'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
'rolename' => 'editingteacher',
],
'Teacher userpicture tag' => [
'templatecontent' => 'Some ##userpicture## tag',
'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
'rolename' => 'editingteacher',
],
'Teacher export tag' => [
'templatecontent' => 'Some ##export## tag',
'expected' => '|Some .*portfolio/add.* tag|',
'rolename' => 'editingteacher',
'enableexport' => true,
],
'Teacher export tag not configured' => [
'templatecontent' => 'Some ##export## tag',
'expected' => '|Some tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
],
'Teacher timeadded tag' => [
'templatecontent' => 'Some ##timeadded## tag',
'expected' => '|Some {timeadded} tag|',
'rolename' => 'editingteacher',
],
'Teacher timemodified tag' => [
'templatecontent' => 'Some ##timemodified## tag',
'expected' => '|Some {timemodified} tag|',
'rolename' => 'editingteacher',
],
'Teacher approve tag approved entry' => [
'templatecontent' => 'Some ##approve## tag',
'expected' => '|Some tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
],
'Teacher approve tag disapproved entry' => [
'templatecontent' => 'Some ##approve## tag',
'expected' => '|Some .*approve.*{entryid}.*sesskey.*Approve.* tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => false,
],
'Teacher disapprove tag approved entry' => [
'templatecontent' => 'Some ##disapprove## tag',
'expected' => '|Some .*disapprove.*{entryid}.*sesskey.*Undo approval.* tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
],
'Teacher disapprove tag disapproved entry' => [
'templatecontent' => 'Some ##disapprove## tag',
'expected' => '|Some tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => false,
],
'Teacher approvalstatus tag approved entry' => [
'templatecontent' => 'Some ##approvalstatus## tag',
'expected' => '|Some Approved tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
],
'Teacher approvalstatus tag disapproved entry' => [
'templatecontent' => 'Some ##approvalstatus## tag',
'expected' => '|Some .*not approved.* tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => false,
],
'Teacher approvalstatusclass tag approved entry' => [
'templatecontent' => 'Some ##approvalstatusclass## tag',
'expected' => '|Some approved tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
],
'Teacher approvalstatusclass tag disapproved entry' => [
'templatecontent' => 'Some ##approvalstatusclass## tag',
'expected' => '|Some notapproved tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => false,
],
'Teacher tags tag' => [
'templatecontent' => 'Some ##tags## tag',
'expected' => '|Some .*Cats.* tag|',
'rolename' => 'editingteacher',
],
'Teacher field name tag' => [
'templatecontent' => 'Some [[myfield]] tag',
'expected' => '|Some .*Example entry.* tag|',
'rolename' => 'editingteacher',
],
'Teacher field#id name tag' => [
'templatecontent' => 'Some [[myfield#id]] tag',
'expected' => '|Some {fieldid} tag|',
'rolename' => 'editingteacher',
],
'Teacher comments name tag with comments enabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some .*Comments.* tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => true,
],
'Teacher comments name tag with comments disabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some tag|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
],
'Teacher comment forced with comments enables' => [
'templatecontent' => 'No tags',
'expected' => '|No tags.*Comments.*|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => true,
'enableratings' => false,
'options' => ['comments' => true],
],
'Teacher comment forced without comments enables' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags$|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => ['comments' => true],
],
'Teacher adding ratings without ratings configured' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags$|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => ['ratings' => true],
],
'Teacher adding ratings with ratings configured' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags.*Average of ratings|',
'rolename' => 'editingteacher',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => true,
'options' => ['ratings' => true],
],
// Student scenarios.
'Student id tag' => [
'templatecontent' => 'Some ##id## tag',
'expected' => '|Some {entryid} tag|',
'rolename' => 'student',
],
'Student delete tag' => [
'templatecontent' => 'Some ##delete## tag',
'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
'rolename' => 'student',
],
'Student delete tag on other author entry' => [
'templatecontent' => 'Some ##delete## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => [],
'otherauthor' => true,
],
'Student edit tag' => [
'templatecontent' => 'Some ##edit## tag',
'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
'rolename' => 'student',
],
'Student edit tag on other author entry' => [
'templatecontent' => 'Some ##edit## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => [],
'otherauthor' => true,
],
'Student more tag' => [
'templatecontent' => 'Some ##more## tag',
'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
'rolename' => 'student',
],
'Student moreurl tag' => [
'templatecontent' => 'Some ##moreurl## tag',
'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
'rolename' => 'student',
],
'Student delcheck tag' => [
'templatecontent' => 'Some ##delcheck## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
],
'Student user tag' => [
'templatecontent' => 'Some ##user## tag',
'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
'rolename' => 'student',
],
'Student userpicture tag' => [
'templatecontent' => 'Some ##userpicture## tag',
'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
'rolename' => 'student',
],
'Student export tag' => [
'templatecontent' => 'Some ##export## tag',
'expected' => '|Some .*portfolio/add.* tag|',
'rolename' => 'student',
'enableexport' => true,
],
'Student export tag not configured' => [
'templatecontent' => 'Some ##export## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
],
'Student export tag on other user entry' => [
'templatecontent' => 'Some ##export## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => true,
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => [],
'otherauthor' => true,
],
'Student timeadded tag' => [
'templatecontent' => 'Some ##timeadded## tag',
'expected' => '|Some {timeadded} tag|',
'rolename' => 'student',
],
'Student timemodified tag' => [
'templatecontent' => 'Some ##timemodified## tag',
'expected' => '|Some {timemodified} tag|',
'rolename' => 'student',
],
'Student approve tag approved entry' => [
'templatecontent' => 'Some ##approve## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
],
'Student approve tag disapproved entry' => [
'templatecontent' => 'Some ##approve## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => false,
],
'Student disapprove tag approved entry' => [
'templatecontent' => 'Some ##disapprove## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
],
'Student disapprove tag disapproved entry' => [
'templatecontent' => 'Some ##disapprove## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => false,
],
'Student approvalstatus tag approved entry' => [
'templatecontent' => 'Some ##approvalstatus## tag',
'expected' => '|Some Approved tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
],
'Student approvalstatus tag disapproved entry' => [
'templatecontent' => 'Some ##approvalstatus## tag',
'expected' => '|Some .*not approved.* tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => false,
],
'Student approvalstatusclass tag approved entry' => [
'templatecontent' => 'Some ##approvalstatusclass## tag',
'expected' => '|Some approved tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
],
'Student approvalstatusclass tag disapproved entry' => [
'templatecontent' => 'Some ##approvalstatusclass## tag',
'expected' => '|Some notapproved tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => false,
],
'Student tags tag' => [
'templatecontent' => 'Some ##tags## tag',
'expected' => '|Some .*Cats.* tag|',
'rolename' => 'student',
],
'Student field name tag' => [
'templatecontent' => 'Some [[myfield]] tag',
'expected' => '|Some .*Example entry.* tag|',
'rolename' => 'student',
],
'Student field#id name tag' => [
'templatecontent' => 'Some [[myfield#id]] tag',
'expected' => '|Some {fieldid} tag|',
'rolename' => 'student',
],
'Student comments name tag with comments enabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some .*Comments.* tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => true,
],
'Student comments name tag with comments disabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some tag|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
],
'Student comment forced with comments enables' => [
'templatecontent' => 'No tags',
'expected' => '|No tags.*Comments.*|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => true,
'enableratings' => false,
'options' => ['comments' => true]
],
'Student comment forced without comments enables' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags$|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => ['comments' => true]
],
'Student adding ratings without ratings configured' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags$|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => false,
'options' => ['ratings' => true]
],
'Student adding ratings with ratings configured' => [
'templatecontent' => 'No tags',
'expected' => '|^No tags$|',
'rolename' => 'student',
'enableexport' => false,
'approved' => true,
'enablecomments' => false,
'enableratings' => true,
'options' => ['ratings' => true]
],
];
}
/**
* Create all the necessary data to enable portfolio export in mod_data
*
* @param stdClass $user the current user record.
*/
protected function enable_portfolio(stdClass $user) {
global $DB;
set_config('enableportfolios', 1);
$plugin = 'download';
$name = 'Download';
$portfolioinstance = (object) [
'plugin' => $plugin,
'name' => $name,
'visible' => 1
];
$portfolioinstance->id = $DB->insert_record('portfolio_instance', $portfolioinstance);
$userinstance = (object) [
'instance' => $portfolioinstance->id,
'userid' => $user->id,
'name' => 'visible',
'value' => 1
];
$DB->insert_record('portfolio_instance_user', $userinstance);
$DB->insert_record('portfolio_log', [
'portfolio' => $portfolioinstance->id,
'userid' => $user->id,
'caller_class' => 'data_portfolio_caller',
'caller_component' => 'mod_data',
'time' => time(),
]);
}
/**
* Enable the ratings on the database entries.
*
* @param context_module $context the activity context
* @param stdClass $activity the activity record
* @param array $entries database entries
* @param stdClass $user the current user record
* @return stdClass the entries with the rating attribute
*/
protected function enable_ratings(context_module $context, stdClass $activity, array $entries, stdClass $user) {
global $CFG;
$ratingoptions = (object)[
'context' => $context,
'component' => 'mod_data',
'ratingarea' => 'entry',
'items' => $entries,
'aggregate' => RATING_AGGREGATE_AVERAGE,
'scaleid' => $activity->scale,
'userid' => $user->id,
'returnurl' => $CFG->wwwroot . '/mod/data/view.php',
'assesstimestart' => $activity->assesstimestart,
'assesstimefinish' => $activity->assesstimefinish,
];
$rm = new rating_manager();
return $rm->get_ratings($ratingoptions);
}
}

View File

@ -3,6 +3,8 @@ information provided here is intended especially for developers.
=== 4.1 ===
* The method data_view is now deprecated. Use $maganer->set_module_viewed instead.
* The data_print_template function is now deprecated and replaced by mod_data\template class.
* The data_print_ratings function now has an extra $print to get the ratings output instead of printing it directly.
=== 3.7 ===
* External functions get_entries, get_entry and search_entries now return an additional field "tags" containing the entry tags.

View File

@ -286,7 +286,8 @@ if ($delete && confirm_sesskey() && (data_user_can_manage_entry($delete, $data,
$deletebutton, 'view.php?d='.$data->id);
$records[] = $deleterecord;
echo data_print_template('singletemplate', $records, $data, '', 0, true);
$parser = $manager->get_template('singletemplate');
echo $parser->parse_entries($records);
echo $OUTPUT->footer();
exit;
@ -329,7 +330,8 @@ if ($multidelete && confirm_sesskey() && $canmanageentries) {
$cancelurl = new moodle_url('/mod/data/view.php', array('d' => $data->id));
$deletebutton = new single_button($action, get_string('delete'));
echo $OUTPUT->confirm(get_string('confirmdeleterecords', 'data'), $deletebutton, $cancelurl);
echo data_print_template('listtemplate', $validrecords, $data, '', 0, false);
$parser = $manager->get_template('listtemplate');
echo $parser->parse_entries($validrecords);
echo $OUTPUT->footer();
exit;
}
@ -459,7 +461,13 @@ if ($showactivity) {
$records = $rm->get_ratings($ratingoptions);
}
data_print_template('singletemplate', $records, $data, $search, $page, false, new moodle_url($baseurl));
$options = [
'search' => $search,
'page' => $page,
'baseurl' => new moodle_url($baseurl),
];
$parser = $manager->get_template('singletemplate', $options);
echo $parser->parse_entries($records);
echo $OUTPUT->paging_bar($totalcount, $page, $nowperpage, $baseurl);
@ -480,7 +488,14 @@ if ($showactivity) {
data_generate_default_template($data, 'listtemplate', 0, false, false);
}
echo $data->listtemplateheader;
data_print_template('listtemplate', $records, $data, $search, $page, false, new moodle_url($baseurl));
$options = [
'search' => $search,
'page' => $page,
'baseurl' => new moodle_url($baseurl),
];
$parser = $manager->get_template('listtemplate', $options);
echo $parser->parse_entries($records);
echo $data->listtemplatefooter;
echo $OUTPUT->paging_bar($totalcount, $page, $nowperpage, $baseurl);