PageRenderTime 32ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 1ms

/mod/data/lib.php

https://bitbucket.org/moodle/moodle
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

  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * @package mod_data
  18. * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
  19. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  20. */
  21. defined('MOODLE_INTERNAL') || die();
  22. // Some constants
  23. define ('DATA_MAX_ENTRIES', 50);
  24. define ('DATA_PERPAGE_SINGLE', 1);
  25. define ('DATA_FIRSTNAME', -1);
  26. define ('DATA_LASTNAME', -2);
  27. define ('DATA_APPROVED', -3);
  28. define ('DATA_TIMEADDED', 0);
  29. define ('DATA_TIMEMODIFIED', -4);
  30. define ('DATA_TAGS', -5);
  31. define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
  32. // Users having assigned the default role "Non-editing teacher" can export database records
  33. // Using the mod/data capability "viewalluserpresets" existing in Moodle 1.9.x.
  34. // In Moodle >= 2, new roles may be introduced and used instead.
  35. define('DATA_PRESET_COMPONENT', 'mod_data');
  36. define('DATA_PRESET_FILEAREA', 'site_presets');
  37. define('DATA_PRESET_CONTEXT', SYSCONTEXTID);
  38. define('DATA_EVENT_TYPE_OPEN', 'open');
  39. define('DATA_EVENT_TYPE_CLOSE', 'close');
  40. require_once(__DIR__ . '/deprecatedlib.php');
  41. /**
  42. * @package mod_data
  43. * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
  44. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  45. */
  46. class data_field_base { // Base class for Database Field Types (see field/*/field.class.php)
  47. /** @var string Subclasses must override the type with their name */
  48. var $type = 'unknown';
  49. /** @var object The database object that this field belongs to */
  50. var $data = NULL;
  51. /** @var object The field object itself, if we know it */
  52. var $field = NULL;
  53. /** @var int Width of the icon for this fieldtype */
  54. var $iconwidth = 16;
  55. /** @var int Width of the icon for this fieldtype */
  56. var $iconheight = 16;
  57. /** @var object course module or cmifno */
  58. var $cm;
  59. /** @var object activity context */
  60. var $context;
  61. /** @var priority for globalsearch indexing */
  62. protected static $priority = self::NO_PRIORITY;
  63. /** priority value for invalid fields regarding indexing */
  64. const NO_PRIORITY = 0;
  65. /** priority value for minimum priority */
  66. const MIN_PRIORITY = 1;
  67. /** priority value for low priority */
  68. const LOW_PRIORITY = 2;
  69. /** priority value for high priority */
  70. const HIGH_PRIORITY = 3;
  71. /** priority value for maximum priority */
  72. const MAX_PRIORITY = 4;
  73. /**
  74. * Constructor function
  75. *
  76. * @global object
  77. * @uses CONTEXT_MODULE
  78. * @param int $field
  79. * @param int $data
  80. * @param int $cm
  81. */
  82. function __construct($field=0, $data=0, $cm=0) { // Field or data or both, each can be id or object
  83. global $DB;
  84. if (empty($field) && empty($data)) {
  85. print_error('missingfield', 'data');
  86. }
  87. if (!empty($field)) {
  88. if (is_object($field)) {
  89. $this->field = $field; // Programmer knows what they are doing, we hope
  90. } else if (!$this->field = $DB->get_record('data_fields', array('id'=>$field))) {
  91. print_error('invalidfieldid', 'data');
  92. }
  93. if (empty($data)) {
  94. if (!$this->data = $DB->get_record('data', array('id'=>$this->field->dataid))) {
  95. print_error('invalidid', 'data');
  96. }
  97. }
  98. }
  99. if (empty($this->data)) { // We need to define this properly
  100. if (!empty($data)) {
  101. if (is_object($data)) {
  102. $this->data = $data; // Programmer knows what they are doing, we hope
  103. } else if (!$this->data = $DB->get_record('data', array('id'=>$data))) {
  104. print_error('invalidid', 'data');
  105. }
  106. } else { // No way to define it!
  107. print_error('missingdata', 'data');
  108. }
  109. }
  110. if ($cm) {
  111. $this->cm = $cm;
  112. } else {
  113. $this->cm = get_coursemodule_from_instance('data', $this->data->id);
  114. }
  115. if (empty($this->field)) { // We need to define some default values
  116. $this->define_default_field();
  117. }
  118. $this->context = context_module::instance($this->cm->id);
  119. }
  120. /**
  121. * This field just sets up a default field object
  122. *
  123. * @return bool
  124. */
  125. function define_default_field() {
  126. global $OUTPUT;
  127. if (empty($this->data->id)) {
  128. echo $OUTPUT->notification('Programmer error: dataid not defined in field class');
  129. }
  130. $this->field = new stdClass();
  131. $this->field->id = 0;
  132. $this->field->dataid = $this->data->id;
  133. $this->field->type = $this->type;
  134. $this->field->param1 = '';
  135. $this->field->param2 = '';
  136. $this->field->param3 = '';
  137. $this->field->name = '';
  138. $this->field->description = '';
  139. $this->field->required = false;
  140. return true;
  141. }
  142. /**
  143. * Set up the field object according to data in an object. Now is the time to clean it!
  144. *
  145. * @return bool
  146. */
  147. function define_field($data) {
  148. $this->field->type = $this->type;
  149. $this->field->dataid = $this->data->id;
  150. $this->field->name = trim($data->name);
  151. $this->field->description = trim($data->description);
  152. $this->field->required = !empty($data->required) ? 1 : 0;
  153. if (isset($data->param1)) {
  154. $this->field->param1 = trim($data->param1);
  155. }
  156. if (isset($data->param2)) {
  157. $this->field->param2 = trim($data->param2);
  158. }
  159. if (isset($data->param3)) {
  160. $this->field->param3 = trim($data->param3);
  161. }
  162. if (isset($data->param4)) {
  163. $this->field->param4 = trim($data->param4);
  164. }
  165. if (isset($data->param5)) {
  166. $this->field->param5 = trim($data->param5);
  167. }
  168. return true;
  169. }
  170. /**
  171. * Insert a new field in the database
  172. * We assume the field object is already defined as $this->field
  173. *
  174. * @global object
  175. * @return bool
  176. */
  177. function insert_field() {
  178. global $DB, $OUTPUT;
  179. if (empty($this->field)) {
  180. echo $OUTPUT->notification('Programmer error: Field has not been defined yet! See define_field()');
  181. return false;
  182. }
  183. $this->field->id = $DB->insert_record('data_fields',$this->field);
  184. // Trigger an event for creating this field.
  185. $event = \mod_data\event\field_created::create(array(
  186. 'objectid' => $this->field->id,
  187. 'context' => $this->context,
  188. 'other' => array(
  189. 'fieldname' => $this->field->name,
  190. 'dataid' => $this->data->id
  191. )
  192. ));
  193. $event->trigger();
  194. return true;
  195. }
  196. /**
  197. * Update a field in the database
  198. *
  199. * @global object
  200. * @return bool
  201. */
  202. function update_field() {
  203. global $DB;
  204. $DB->update_record('data_fields', $this->field);
  205. // Trigger an event for updating this field.
  206. $event = \mod_data\event\field_updated::create(array(
  207. 'objectid' => $this->field->id,
  208. 'context' => $this->context,
  209. 'other' => array(
  210. 'fieldname' => $this->field->name,
  211. 'dataid' => $this->data->id
  212. )
  213. ));
  214. $event->trigger();
  215. return true;
  216. }
  217. /**
  218. * Delete a field completely
  219. *
  220. * @global object
  221. * @return bool
  222. */
  223. function delete_field() {
  224. global $DB;
  225. if (!empty($this->field->id)) {
  226. // Get the field before we delete it.
  227. $field = $DB->get_record('data_fields', array('id' => $this->field->id));
  228. $this->delete_content();
  229. $DB->delete_records('data_fields', array('id'=>$this->field->id));
  230. // Trigger an event for deleting this field.
  231. $event = \mod_data\event\field_deleted::create(array(
  232. 'objectid' => $this->field->id,
  233. 'context' => $this->context,
  234. 'other' => array(
  235. 'fieldname' => $this->field->name,
  236. 'dataid' => $this->data->id
  237. )
  238. ));
  239. $event->add_record_snapshot('data_fields', $field);
  240. $event->trigger();
  241. }
  242. return true;
  243. }
  244. /**
  245. * Print the relevant form element in the ADD template for this field
  246. *
  247. * @global object
  248. * @param int $recordid
  249. * @return string
  250. */
  251. function display_add_field($recordid=0, $formdata=null) {
  252. global $DB, $OUTPUT;
  253. if ($formdata) {
  254. $fieldname = 'field_' . $this->field->id;
  255. $content = $formdata->$fieldname;
  256. } else if ($recordid) {
  257. $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
  258. } else {
  259. $content = '';
  260. }
  261. // beware get_field returns false for new, empty records MDL-18567
  262. if ($content===false) {
  263. $content='';
  264. }
  265. $str = '<div title="' . s($this->field->description) . '">';
  266. $str .= '<label for="field_'.$this->field->id.'"><span class="accesshide">'.$this->field->name.'</span>';
  267. if ($this->field->required) {
  268. $image = $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
  269. $str .= html_writer::div($image, 'inline-req');
  270. }
  271. $str .= '</label><input class="basefieldinput form-control d-inline mod-data-input" ' .
  272. 'type="text" name="field_' . $this->field->id . '" ' .
  273. 'id="field_' . $this->field->id . '" value="' . s($content) . '" />';
  274. $str .= '</div>';
  275. return $str;
  276. }
  277. /**
  278. * Print the relevant form element to define the attributes for this field
  279. * viewable by teachers only.
  280. *
  281. * @global object
  282. * @global object
  283. * @return void Output is echo'd
  284. */
  285. function display_edit_field() {
  286. global $CFG, $DB, $OUTPUT;
  287. if (empty($this->field)) { // No field has been defined yet, try and make one
  288. $this->define_default_field();
  289. }
  290. echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
  291. echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
  292. echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
  293. if (empty($this->field->id)) {
  294. echo '<input type="hidden" name="mode" value="add" />'."\n";
  295. $savebutton = get_string('add');
  296. } else {
  297. echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
  298. echo '<input type="hidden" name="mode" value="update" />'."\n";
  299. $savebutton = get_string('savechanges');
  300. }
  301. echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
  302. echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
  303. echo $OUTPUT->heading($this->name(), 3);
  304. require_once($CFG->dirroot.'/mod/data/field/'.$this->type.'/mod.html');
  305. echo html_writer::start_div('mt-3');
  306. echo html_writer::tag('input', null, array('type' => 'submit', 'value' => $savebutton,
  307. 'class' => 'btn btn-primary'));
  308. echo html_writer::tag('input', null, array('type' => 'submit', 'name' => 'cancel',
  309. 'value' => get_string('cancel'), 'class' => 'btn btn-secondary ml-2'));
  310. echo html_writer::end_div();
  311. echo '</form>';
  312. echo $OUTPUT->box_end();
  313. }
  314. /**
  315. * Display the content of the field in browse mode
  316. *
  317. * @global object
  318. * @param int $recordid
  319. * @param object $template
  320. * @return bool|string
  321. */
  322. function display_browse_field($recordid, $template) {
  323. global $DB;
  324. if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
  325. if (isset($content->content)) {
  326. $options = new stdClass();
  327. if ($this->field->param1 == '1') { // We are autolinking this field, so disable linking within us
  328. //$content->content = '<span class="nolink">'.$content->content.'</span>';
  329. //$content->content1 = FORMAT_HTML;
  330. $options->filter=false;
  331. }
  332. $options->para = false;
  333. $str = format_text($content->content, $content->content1, $options);
  334. } else {
  335. $str = '';
  336. }
  337. return $str;
  338. }
  339. return false;
  340. }
  341. /**
  342. * Update the content of one data field in the data_content table
  343. * @global object
  344. * @param int $recordid
  345. * @param mixed $value
  346. * @param string $name
  347. * @return bool
  348. */
  349. function update_content($recordid, $value, $name=''){
  350. global $DB;
  351. $content = new stdClass();
  352. $content->fieldid = $this->field->id;
  353. $content->recordid = $recordid;
  354. $content->content = clean_param($value, PARAM_NOTAGS);
  355. if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
  356. $content->id = $oldcontent->id;
  357. return $DB->update_record('data_content', $content);
  358. } else {
  359. return $DB->insert_record('data_content', $content);
  360. }
  361. }
  362. /**
  363. * Delete all content associated with the field
  364. *
  365. * @global object
  366. * @param int $recordid
  367. * @return bool
  368. */
  369. function delete_content($recordid=0) {
  370. global $DB;
  371. if ($recordid) {
  372. $conditions = array('fieldid'=>$this->field->id, 'recordid'=>$recordid);
  373. } else {
  374. $conditions = array('fieldid'=>$this->field->id);
  375. }
  376. $rs = $DB->get_recordset('data_content', $conditions);
  377. if ($rs->valid()) {
  378. $fs = get_file_storage();
  379. foreach ($rs as $content) {
  380. $fs->delete_area_files($this->context->id, 'mod_data', 'content', $content->id);
  381. }
  382. }
  383. $rs->close();
  384. return $DB->delete_records('data_content', $conditions);
  385. }
  386. /**
  387. * Check if a field from an add form is empty
  388. *
  389. * @param mixed $value
  390. * @param mixed $name
  391. * @return bool
  392. */
  393. function notemptyfield($value, $name) {
  394. return !empty($value);
  395. }
  396. /**
  397. * Just in case a field needs to print something before the whole form
  398. */
  399. function print_before_form() {
  400. }
  401. /**
  402. * Just in case a field needs to print something after the whole form
  403. */
  404. function print_after_form() {
  405. }
  406. /**
  407. * Returns the sortable field for the content. By default, it's just content
  408. * but for some plugins, it could be content 1 - content4
  409. *
  410. * @return string
  411. */
  412. function get_sort_field() {
  413. return 'content';
  414. }
  415. /**
  416. * Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
  417. *
  418. * @param string $fieldname
  419. * @return string $fieldname
  420. */
  421. function get_sort_sql($fieldname) {
  422. return $fieldname;
  423. }
  424. /**
  425. * Returns the name/type of the field
  426. *
  427. * @return string
  428. */
  429. function name() {
  430. return get_string('fieldtypelabel', "datafield_$this->type");
  431. }
  432. /**
  433. * Prints the respective type icon
  434. *
  435. * @global object
  436. * @return string
  437. */
  438. function image() {
  439. global $OUTPUT;
  440. $params = array('d'=>$this->data->id, 'fid'=>$this->field->id, 'mode'=>'display', 'sesskey'=>sesskey());
  441. $link = new moodle_url('/mod/data/field.php', $params);
  442. $str = '<a href="'.$link->out().'">';
  443. $str .= $OUTPUT->pix_icon('field/' . $this->type, $this->type, 'data');
  444. $str .= '</a>';
  445. return $str;
  446. }
  447. /**
  448. * Per default, it is assumed that fields support text exporting.
  449. * Override this (return false) on fields not supporting text exporting.
  450. *
  451. * @return bool true
  452. */
  453. function text_export_supported() {
  454. return true;
  455. }
  456. /**
  457. * Per default, return the record's text value only from the "content" field.
  458. * Override this in fields class if necesarry.
  459. *
  460. * @param string $record
  461. * @return string
  462. */
  463. function export_text_value($record) {
  464. if ($this->text_export_supported()) {
  465. return $record->content;
  466. }
  467. }
  468. /**
  469. * @param string $relativepath
  470. * @return bool false
  471. */
  472. function file_ok($relativepath) {
  473. return false;
  474. }
  475. /**
  476. * Returns the priority for being indexed by globalsearch
  477. *
  478. * @return int
  479. */
  480. public static function get_priority() {
  481. return static::$priority;
  482. }
  483. /**
  484. * Returns the presentable string value for a field content.
  485. *
  486. * The returned string should be plain text.
  487. *
  488. * @param stdClass $content
  489. * @return string
  490. */
  491. public static function get_content_value($content) {
  492. return trim($content->content, "\r\n ");
  493. }
  494. /**
  495. * Return the plugin configs for external functions,
  496. * in some cases the configs will need formatting or be returned only if the current user has some capabilities enabled.
  497. *
  498. * @return array the list of config parameters
  499. * @since Moodle 3.3
  500. */
  501. public function get_config_for_external() {
  502. // Return all the field configs to null (maybe there is a private key for a service or something similar there).
  503. $configs = [];
  504. for ($i = 1; $i <= 10; $i++) {
  505. $configs["param$i"] = null;
  506. }
  507. return $configs;
  508. }
  509. }
  510. /**
  511. * Given a template and a dataid, generate a default case template
  512. *
  513. * @global object
  514. * @param object $data
  515. * @param string template [addtemplate, singletemplate, listtempalte, rsstemplate]
  516. * @param int $recordid
  517. * @param bool $form
  518. * @param bool $update
  519. * @return bool|string
  520. */
  521. function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
  522. global $DB;
  523. if (!$data && !$template) {
  524. return false;
  525. }
  526. if ($template == 'csstemplate' or $template == 'jstemplate' ) {
  527. return '';
  528. }
  529. // get all the fields for that database
  530. if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id), 'id')) {
  531. $table = new html_table();
  532. $table->attributes['class'] = 'mod-data-default-template ##approvalstatusclass##';
  533. $table->colclasses = array('template-field', 'template-token');
  534. $table->data = array();
  535. foreach ($fields as $field) {
  536. if ($form) { // Print forms instead of data
  537. $fieldobj = data_get_field($field, $data);
  538. $token = $fieldobj->display_add_field($recordid, null);
  539. } else { // Just print the tag
  540. $token = '[['.$field->name.']]';
  541. }
  542. $table->data[] = array(
  543. $field->name.': ',
  544. $token
  545. );
  546. }
  547. if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
  548. $label = new html_table_cell(get_string('tags') . ':');
  549. if ($form) {
  550. $cell = data_generate_tag_form();
  551. } else {
  552. $cell = new html_table_cell('##tags##');
  553. }
  554. $table->data[] = new html_table_row(array($label, $cell));
  555. }
  556. if ($template == 'listtemplate') {
  557. $cell = new html_table_cell('##edit## ##more## ##delete## ##approve## ##disapprove## ##export##');
  558. $cell->colspan = 2;
  559. $cell->attributes['class'] = 'controls';
  560. $table->data[] = new html_table_row(array($cell));
  561. } else if ($template == 'singletemplate') {
  562. $cell = new html_table_cell('##edit## ##delete## ##approve## ##disapprove## ##export##');
  563. $cell->colspan = 2;
  564. $cell->attributes['class'] = 'controls';
  565. $table->data[] = new html_table_row(array($cell));
  566. } else if ($template == 'asearchtemplate') {
  567. $row = new html_table_row(array(get_string('authorfirstname', 'data').': ', '##firstname##'));
  568. $row->attributes['class'] = 'searchcontrols';
  569. $table->data[] = $row;
  570. $row = new html_table_row(array(get_string('authorlastname', 'data').': ', '##lastname##'));
  571. $row->attributes['class'] = 'searchcontrols';
  572. $table->data[] = $row;
  573. }
  574. $str = '';
  575. if ($template == 'listtemplate'){
  576. $str .= '##delcheck##';
  577. $str .= html_writer::empty_tag('br');
  578. }
  579. $str .= html_writer::start_tag('div', array('class' => 'defaulttemplate'));
  580. $str .= html_writer::table($table);
  581. $str .= html_writer::end_tag('div');
  582. if ($template == 'listtemplate'){
  583. $str .= html_writer::empty_tag('hr');
  584. }
  585. if ($update) {
  586. $newdata = new stdClass();
  587. $newdata->id = $data->id;
  588. $newdata->{$template} = $str;
  589. $DB->update_record('data', $newdata);
  590. $data->{$template} = $str;
  591. }
  592. return $str;
  593. }
  594. }
  595. /**
  596. * Build the form elements to manage tags for a record.
  597. *
  598. * @param int|bool $recordid
  599. * @param string[] $selected raw tag names
  600. * @return string
  601. */
  602. function data_generate_tag_form($recordid = false, $selected = []) {
  603. global $CFG, $DB, $OUTPUT, $PAGE;
  604. $tagtypestoshow = \core_tag_area::get_showstandard('mod_data', 'data_records');
  605. $showstandard = ($tagtypestoshow != core_tag_tag::HIDE_STANDARD);
  606. $typenewtags = ($tagtypestoshow != core_tag_tag::STANDARD_ONLY);
  607. $str = html_writer::start_tag('div', array('class' => 'datatagcontrol'));
  608. $namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
  609. $tagcollid = \core_tag_area::get_collection('mod_data', 'data_records');
  610. $tags = [];
  611. $selectedtags = [];
  612. if ($showstandard) {
  613. $tags += $DB->get_records_menu('tag', array('isstandard' => 1, 'tagcollid' => $tagcollid),
  614. $namefield, 'id,' . $namefield . ' as fieldname');
  615. }
  616. if ($recordid) {
  617. $selectedtags += core_tag_tag::get_item_tags_array('mod_data', 'data_records', $recordid);
  618. }
  619. if (!empty($selected)) {
  620. list($sql, $params) = $DB->get_in_or_equal($selected, SQL_PARAMS_NAMED);
  621. $params['tagcollid'] = $tagcollid;
  622. $sql = "SELECT id, $namefield FROM {tag} WHERE tagcollid = :tagcollid AND rawname $sql";
  623. $selectedtags += $DB->get_records_sql_menu($sql, $params);
  624. }
  625. $tags += $selectedtags;
  626. $str .= '<select class="custom-select" name="tags[]" id="tags" multiple>';
  627. foreach ($tags as $tagid => $tag) {
  628. $selected = key_exists($tagid, $selectedtags) ? 'selected' : '';
  629. $str .= "<option value='$tag' $selected>$tag</option>";
  630. }
  631. $str .= '</select>';
  632. if (has_capability('moodle/tag:manage', context_system::instance()) && $showstandard) {
  633. $url = new moodle_url('/tag/manage.php', array('tc' => core_tag_area::get_collection('mod_data',
  634. 'data_records')));
  635. $str .= ' ' . $OUTPUT->action_link($url, get_string('managestandardtags', 'tag'));
  636. }
  637. $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array(
  638. '#tags',
  639. $typenewtags,
  640. '',
  641. get_string('entertags', 'tag'),
  642. false,
  643. $showstandard,
  644. get_string('noselection', 'form')
  645. )
  646. );
  647. $str .= html_writer::end_tag('div');
  648. return $str;
  649. }
  650. /**
  651. * Search for a field name and replaces it with another one in all the
  652. * form templates. Set $newfieldname as '' if you want to delete the
  653. * field from the form.
  654. *
  655. * @global object
  656. * @param object $data
  657. * @param string $searchfieldname
  658. * @param string $newfieldname
  659. * @return bool
  660. */
  661. function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
  662. global $DB;
  663. if (!empty($newfieldname)) {
  664. $prestring = '[[';
  665. $poststring = ']]';
  666. $idpart = '#id';
  667. } else {
  668. $prestring = '';
  669. $poststring = '';
  670. $idpart = '';
  671. }
  672. $newdata = new stdClass();
  673. $newdata->id = $data->id;
  674. $newdata->singletemplate = str_ireplace('[['.$searchfieldname.']]',
  675. $prestring.$newfieldname.$poststring, $data->singletemplate);
  676. $newdata->listtemplate = str_ireplace('[['.$searchfieldname.']]',
  677. $prestring.$newfieldname.$poststring, $data->listtemplate);
  678. $newdata->addtemplate = str_ireplace('[['.$searchfieldname.']]',
  679. $prestring.$newfieldname.$poststring, $data->addtemplate);
  680. $newdata->addtemplate = str_ireplace('[['.$searchfieldname.'#id]]',
  681. $prestring.$newfieldname.$idpart.$poststring, $data->addtemplate);
  682. $newdata->rsstemplate = str_ireplace('[['.$searchfieldname.']]',
  683. $prestring.$newfieldname.$poststring, $data->rsstemplate);
  684. return $DB->update_record('data', $newdata);
  685. }
  686. /**
  687. * Appends a new field at the end of the form template.
  688. *
  689. * @global object
  690. * @param object $data
  691. * @param string $newfieldname
  692. */
  693. function data_append_new_field_to_templates($data, $newfieldname) {
  694. global $DB;
  695. $newdata = new stdClass();
  696. $newdata->id = $data->id;
  697. $change = false;
  698. if (!empty($data->singletemplate)) {
  699. $newdata->singletemplate = $data->singletemplate.' [[' . $newfieldname .']]';
  700. $change = true;
  701. }
  702. if (!empty($data->addtemplate)) {
  703. $newdata->addtemplate = $data->addtemplate.' [[' . $newfieldname . ']]';
  704. $change = true;
  705. }
  706. if (!empty($data->rsstemplate)) {
  707. $newdata->rsstemplate = $data->singletemplate.' [[' . $newfieldname . ']]';
  708. $change = true;
  709. }
  710. if ($change) {
  711. $DB->update_record('data', $newdata);
  712. }
  713. }
  714. /**
  715. * given a field name
  716. * this function creates an instance of the particular subfield class
  717. *
  718. * @global object
  719. * @param string $name
  720. * @param object $data
  721. * @return object|bool
  722. */
  723. function data_get_field_from_name($name, $data){
  724. global $DB;
  725. $field = $DB->get_record('data_fields', array('name'=>$name, 'dataid'=>$data->id));
  726. if ($field) {
  727. return data_get_field($field, $data);
  728. } else {
  729. return false;
  730. }
  731. }
  732. /**
  733. * given a field id
  734. * this function creates an instance of the particular subfield class
  735. *
  736. * @global object
  737. * @param int $fieldid
  738. * @param object $data
  739. * @return bool|object
  740. */
  741. function data_get_field_from_id($fieldid, $data){
  742. global $DB;
  743. $field = $DB->get_record('data_fields', array('id'=>$fieldid, 'dataid'=>$data->id));
  744. if ($field) {
  745. return data_get_field($field, $data);
  746. } else {
  747. return false;
  748. }
  749. }
  750. /**
  751. * given a field id
  752. * this function creates an instance of the particular subfield class
  753. *
  754. * @global object
  755. * @param string $type
  756. * @param object $data
  757. * @return object
  758. */
  759. function data_get_field_new($type, $data) {
  760. global $CFG;
  761. require_once($CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php');
  762. $newfield = 'data_field_'.$type;
  763. $newfield = new $newfield(0, $data);
  764. return $newfield;
  765. }
  766. /**
  767. * returns a subclass field object given a record of the field, used to
  768. * invoke plugin methods
  769. * input: $param $field - record from db
  770. *
  771. * @global object
  772. * @param object $field
  773. * @param object $data
  774. * @param object $cm
  775. * @return object
  776. */
  777. function data_get_field($field, $data, $cm=null) {
  778. global $CFG;
  779. if ($field) {
  780. require_once('field/'.$field->type.'/field.class.php');
  781. $newfield = 'data_field_'.$field->type;
  782. $newfield = new $newfield($field, $data, $cm);
  783. return $newfield;
  784. }
  785. }
  786. /**
  787. * Given record object (or id), returns true if the record belongs to the current user
  788. *
  789. * @global object
  790. * @global object
  791. * @param mixed $record record object or id
  792. * @return bool
  793. */
  794. function data_isowner($record) {
  795. global $USER, $DB;
  796. if (!isloggedin()) { // perf shortcut
  797. return false;
  798. }
  799. if (!is_object($record)) {
  800. if (!$record = $DB->get_record('data_records', array('id'=>$record))) {
  801. return false;
  802. }
  803. }
  804. return ($record->userid == $USER->id);
  805. }
  806. /**
  807. * has a user reached the max number of entries?
  808. *
  809. * @param object $data
  810. * @return bool
  811. */
  812. function data_atmaxentries($data){
  813. if (!$data->maxentries){
  814. return false;
  815. } else {
  816. return (data_numentries($data) >= $data->maxentries);
  817. }
  818. }
  819. /**
  820. * returns the number of entries already made by this user
  821. *
  822. * @global object
  823. * @global object
  824. * @param object $data
  825. * @return int
  826. */
  827. function data_numentries($data, $userid=null) {
  828. global $USER, $DB;
  829. if ($userid === null) {
  830. $userid = $USER->id;
  831. }
  832. $sql = 'SELECT COUNT(*) FROM {data_records} WHERE dataid=? AND userid=?';
  833. return $DB->count_records_sql($sql, array($data->id, $userid));
  834. }
  835. /**
  836. * function that takes in a dataid and adds a record
  837. * this is used everytime an add template is submitted
  838. *
  839. * @global object
  840. * @global object
  841. * @param object $data
  842. * @param int $groupid
  843. * @param int $userid
  844. * @return bool
  845. */
  846. function data_add_record($data, $groupid = 0, $userid = null) {
  847. global $USER, $DB;
  848. $cm = get_coursemodule_from_instance('data', $data->id);
  849. $context = context_module::instance($cm->id);
  850. $record = new stdClass();
  851. $record->userid = $userid ?? $USER->id;
  852. $record->dataid = $data->id;
  853. $record->groupid = $groupid;
  854. $record->timecreated = $record->timemodified = time();
  855. if (has_capability('mod/data:approve', $context)) {
  856. $record->approved = 1;
  857. } else {
  858. $record->approved = 0;
  859. }
  860. $record->id = $DB->insert_record('data_records', $record);
  861. // Trigger an event for creating this record.
  862. $event = \mod_data\event\record_created::create(array(
  863. 'objectid' => $record->id,
  864. 'context' => $context,
  865. 'other' => array(
  866. 'dataid' => $data->id
  867. )
  868. ));
  869. $event->trigger();
  870. $course = get_course($cm->course);
  871. data_update_completion_state($data, $course, $cm);
  872. return $record->id;
  873. }
  874. /**
  875. * check the multple existence any tag in a template
  876. *
  877. * check to see if there are 2 or more of the same tag being used.
  878. *
  879. * @global object
  880. * @param int $dataid,
  881. * @param string $template
  882. * @return bool
  883. */
  884. function data_tags_check($dataid, $template) {
  885. global $DB, $OUTPUT;
  886. // first get all the possible tags
  887. $fields = $DB->get_records('data_fields', array('dataid'=>$dataid));
  888. // then we generate strings to replace
  889. $tagsok = true; // let's be optimistic
  890. foreach ($fields as $field){
  891. $pattern="/\[\[" . preg_quote($field->name, '/') . "\]\]/i";
  892. if (preg_match_all($pattern, $template, $dummy)>1){
  893. $tagsok = false;
  894. echo $OUTPUT->notification('[['.$field->name.']] - '.get_string('multipletags','data'));
  895. }
  896. }
  897. // else return true
  898. return $tagsok;
  899. }
  900. /**
  901. * Adds an instance of a data
  902. *
  903. * @param stdClass $data
  904. * @param mod_data_mod_form $mform
  905. * @return int intance id
  906. */
  907. function data_add_instance($data, $mform = null) {
  908. global $DB, $CFG;
  909. require_once($CFG->dirroot.'/mod/data/locallib.php');
  910. if (empty($data->assessed)) {
  911. $data->assessed = 0;
  912. }
  913. if (empty($data->ratingtime) || empty($data->assessed)) {
  914. $data->assesstimestart = 0;
  915. $data->assesstimefinish = 0;
  916. }
  917. $data->timemodified = time();
  918. $data->id = $DB->insert_record('data', $data);
  919. // Add calendar events if necessary.
  920. data_set_events($data);
  921. if (!empty($data->completionexpected)) {
  922. \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $data->completionexpected);
  923. }
  924. data_grade_item_update($data);
  925. return $data->id;
  926. }
  927. /**
  928. * updates an instance of a data
  929. *
  930. * @global object
  931. * @param object $data
  932. * @return bool
  933. */
  934. function data_update_instance($data) {
  935. global $DB, $CFG;
  936. require_once($CFG->dirroot.'/mod/data/locallib.php');
  937. $data->timemodified = time();
  938. $data->id = $data->instance;
  939. if (empty($data->assessed)) {
  940. $data->assessed = 0;
  941. }
  942. if (empty($data->ratingtime) or empty($data->assessed)) {
  943. $data->assesstimestart = 0;
  944. $data->assesstimefinish = 0;
  945. }
  946. if (empty($data->notification)) {
  947. $data->notification = 0;
  948. }
  949. $DB->update_record('data', $data);
  950. // Add calendar events if necessary.
  951. data_set_events($data);
  952. $completionexpected = (!empty($data->completionexpected)) ? $data->completionexpected : null;
  953. \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $completionexpected);
  954. data_grade_item_update($data);
  955. return true;
  956. }
  957. /**
  958. * deletes an instance of a data
  959. *
  960. * @global object
  961. * @param int $id
  962. * @return bool
  963. */
  964. function data_delete_instance($id) { // takes the dataid
  965. global $DB, $CFG;
  966. if (!$data = $DB->get_record('data', array('id'=>$id))) {
  967. return false;
  968. }
  969. $cm = get_coursemodule_from_instance('data', $data->id);
  970. $context = context_module::instance($cm->id);
  971. /// Delete all the associated information
  972. // files
  973. $fs = get_file_storage();
  974. $fs->delete_area_files($context->id, 'mod_data');
  975. // get all the records in this data
  976. $sql = "SELECT r.id
  977. FROM {data_records} r
  978. WHERE r.dataid = ?";
  979. $DB->delete_records_select('data_content', "recordid IN ($sql)", array($id));
  980. // delete all the records and fields
  981. $DB->delete_records('data_records', array('dataid'=>$id));
  982. $DB->delete_records('data_fields', array('dataid'=>$id));
  983. // Remove old calendar events.
  984. $events = $DB->get_records('event', array('modulename' => 'data', 'instance' => $id));
  985. foreach ($events as $event) {
  986. $event = calendar_event::load($event);
  987. $event->delete();
  988. }
  989. // cleanup gradebook
  990. data_grade_item_delete($data);
  991. // Delete the instance itself
  992. // We must delete the module record after we delete the grade item.
  993. $result = $DB->delete_records('data', array('id'=>$id));
  994. return $result;
  995. }
  996. /**
  997. * returns a summary of data activity of this user
  998. *
  999. * @global object
  1000. * @param object $course
  1001. * @param object $user
  1002. * @param object $mod
  1003. * @param object $data
  1004. * @return object|null
  1005. */
  1006. function data_user_outline($course, $user, $mod, $data) {
  1007. global $DB, $CFG;
  1008. require_once("$CFG->libdir/gradelib.php");
  1009. $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
  1010. if (empty($grades->items[0]->grades)) {
  1011. $grade = false;
  1012. } else {
  1013. $grade = reset($grades->items[0]->grades);
  1014. }
  1015. if ($countrecords = $DB->count_records('data_records', array('dataid'=>$data->id, 'userid'=>$user->id))) {
  1016. $result = new stdClass();
  1017. $result->info = get_string('numrecords', 'data', $countrecords);
  1018. $lastrecord = $DB->get_record_sql('SELECT id,timemodified FROM {data_records}
  1019. WHERE dataid = ? AND userid = ?
  1020. ORDER BY timemodified DESC', array($data->id, $user->id), true);
  1021. $result->time = $lastrecord->timemodified;
  1022. if ($grade) {
  1023. if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
  1024. $result->info .= ', ' . get_string('gradenoun') . ': ' . $grade->str_long_grade;
  1025. } else {
  1026. $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
  1027. }
  1028. }
  1029. return $result;
  1030. } else if ($grade) {
  1031. $result = (object) [
  1032. 'time' => grade_get_date_for_user_grade($grade, $user),
  1033. ];
  1034. if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
  1035. $result->info = get_string('gradenoun') . ': ' . $grade->str_long_grade;
  1036. } else {
  1037. $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
  1038. }
  1039. return $result;
  1040. }
  1041. return NULL;
  1042. }
  1043. /**
  1044. * Prints all the records uploaded by this user
  1045. *
  1046. * @global object
  1047. * @param object $course
  1048. * @param object $user
  1049. * @param object $mod
  1050. * @param object $data
  1051. */
  1052. function data_user_complete($course, $user, $mod, $data) {
  1053. global $DB, $CFG, $OUTPUT;
  1054. require_once("$CFG->libdir/gradelib.php");
  1055. $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
  1056. if (!empty($grades->items[0]->grades)) {
  1057. $grade = reset($grades->items[0]->grades);
  1058. if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
  1059. echo $OUTPUT->container(get_string('gradenoun') . ': ' . $grade->str_long_grade);
  1060. if ($grade->str_feedback) {
  1061. echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
  1062. }
  1063. } else {
  1064. echo $OUTPUT->container(get_string('gradenoun') . ': ' . get_string('hidden', 'grades'));
  1065. }
  1066. }
  1067. if ($records = $DB->get_records('data_records', array('dataid'=>$data->id,'userid'=>$user->id), 'timemodified DESC')) {
  1068. data_print_template('singletemplate', $records, $data);
  1069. }
  1070. }
  1071. /**
  1072. * Return grade for given user or all users.
  1073. *
  1074. * @global object
  1075. * @param object $data
  1076. * @param int $userid optional user id, 0 means all users
  1077. * @return array array of grades, false if none
  1078. */
  1079. function data_get_user_grades($data, $userid=0) {
  1080. global $CFG;
  1081. require_once($CFG->dirroot.'/rating/lib.php');
  1082. $ratingoptions = new stdClass;
  1083. $ratingoptions->component = 'mod_data';
  1084. $ratingoptions->ratingarea = 'entry';
  1085. $ratingoptions->modulename = 'data';
  1086. $ratingoptions->moduleid = $data->id;
  1087. $ratingoptions->userid = $userid;
  1088. $ratingoptions->aggregationmethod = $data->assessed;
  1089. $ratingoptions->scaleid = $data->scale;
  1090. $ratingoptions->itemtable = 'data_records';
  1091. $ratingoptions->itemtableusercolumn = 'userid';
  1092. $rm = new rating_manager();
  1093. return $rm->get_user_grades($ratingoptions);
  1094. }
  1095. /**
  1096. * Update activity grades
  1097. *
  1098. * @category grade
  1099. * @param object $data
  1100. * @param int $userid specific user only, 0 means all
  1101. * @param bool $nullifnone
  1102. */
  1103. function data_update_grades($data, $userid=0, $nullifnone=true) {
  1104. global $CFG, $DB;
  1105. require_once($CFG->libdir.'/gradelib.php');
  1106. if (!$data->assessed) {
  1107. data_grade_item_update($data);
  1108. } else if ($grades = data_get_user_grades($data, $userid)) {
  1109. data_grade_item_update($data, $grades);
  1110. } else if ($userid and $nullifnone) {
  1111. $grade = new stdClass();
  1112. $grade->userid = $userid;
  1113. $grade->rawgrade = NULL;
  1114. data_grade_item_update($data, $grade);
  1115. } else {
  1116. data_grade_item_update($data);
  1117. }
  1118. }
  1119. /**
  1120. * Update/create grade item for given data
  1121. *
  1122. * @category grade
  1123. * @param stdClass $data A database instance with extra cmidnumber property
  1124. * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
  1125. * @return object grade_item
  1126. */
  1127. function data_grade_item_update($data, $grades=NULL) {
  1128. global $CFG;
  1129. require_once($CFG->libdir.'/gradelib.php');
  1130. $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
  1131. if (!$data->assessed or $data->scale == 0) {
  1132. $params['gradetype'] = GRADE_TYPE_NONE;
  1133. } else if ($data->scale > 0) {
  1134. $params['gradetype'] = GRADE_TYPE_VALUE;
  1135. $params['grademax'] = $data->scale;
  1136. $params['grademin'] = 0;
  1137. } else if ($data->scale < 0) {
  1138. $params['gradetype'] = GRADE_TYPE_SCALE;
  1139. $params['scaleid'] = -$data->scale;
  1140. }
  1141. if ($grades === 'reset') {
  1142. $params['reset'] = true;
  1143. $grades = NULL;
  1144. }
  1145. return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades, $params);
  1146. }
  1147. /**
  1148. * Delete grade item for given data
  1149. *
  1150. * @category grade
  1151. * @param object $data object
  1152. * @return object grade_item
  1153. */
  1154. function data_grade_item_delete($data) {
  1155. global $CFG;
  1156. require_once($CFG->libdir.'/gradelib.php');
  1157. return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
  1158. }
  1159. // junk functions
  1160. /**
  1161. * takes a list of records, the current data, a search string,
  1162. * and mode to display prints the translated template
  1163. *
  1164. * @global object
  1165. * @global object
  1166. * @param string $template
  1167. * @param array $records
  1168. * @param object $data
  1169. * @param string $search
  1170. * @param int $page
  1171. * @param bool $return
  1172. * @param object $jumpurl a moodle_url by which to jump back to the record list (can be null)
  1173. * @return mixed
  1174. */
  1175. function data_print_template($template, $records, $data, $search='', $page=0, $return=false, moodle_url $jumpurl=null) {
  1176. global $CFG, $DB, $OUTPUT;
  1177. $cm = get_coursemodule_from_instance('data', $data->id);
  1178. $context = context_module::instance($cm->id);
  1179. static $fields = array();
  1180. static $dataid = null;
  1181. if (empty($dataid)) {
  1182. $dataid = $data->id;
  1183. } else if ($dataid != $data->id) {
  1184. $fields = array();
  1185. }
  1186. if (empty($fields)) {
  1187. $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$data->id));
  1188. foreach ($fieldrecords as $fieldrecord) {
  1189. $fields[]= data_get_field($fieldrecord, $data);
  1190. }
  1191. }
  1192. if (empty($records)) {
  1193. return;
  1194. }
  1195. if (!$jumpurl) {
  1196. $jumpurl = new moodle_url('/mod/data/view.php', array('d' => $data->id));
  1197. }
  1198. $jumpurl = new moodle_url($jumpurl, array('page' => $page, 'sesskey' => sesskey()));
  1199. foreach ($records as $record) { // Might be just one for the single template
  1200. // Replacing tags
  1201. $patterns = array();
  1202. $replacement = array();
  1203. // Then we generate strings to replace for normal tags
  1204. foreach ($fields as $field) {
  1205. $patterns[]='[['.$field->field->name.']]';
  1206. $replacement[] = highlight($search, $field->display_browse_field($record->id, $template));
  1207. }
  1208. $canmanageentries = has_capability('mod/data:manageentries', $context);
  1209. // Replacing special tags (##Edit##, ##Delete##, ##More##)
  1210. $patterns[]='##edit##';
  1211. $patterns[]='##delete##';
  1212. if (data_user_can_manage_entry($record, $data, $context)) {
  1213. $backtourlparams = [
  1214. 'd' => $data->id,
  1215. ];
  1216. if ($template === 'singletemplate') {
  1217. $backtourlparams['mode'] = 'single';
  1218. }
  1219. $backtourl = new \moodle_url('/mod/data/view.php', $backtourlparams);
  1220. $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
  1221. .$data->id.'&amp;rid='.$record->id.'&amp;sesskey='.sesskey().'&amp;backto='
  1222. . urlencode($backtourl->out(false)) .'">' .
  1223. $OUTPUT->pix_icon('t/edit', get_string('edit')) . '</a>';
  1224. $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
  1225. .$data->id.'&amp;delete='.$record->id.'&amp;sesskey='.sesskey().'">' .
  1226. $OUTPUT->pix_icon('t/delete', get_string('delete')) . '</a>';
  1227. } else {
  1228. $replacement[] = '';
  1229. $replacement[] = '';
  1230. }
  1231. $moreurl = $CFG->wwwroot . '/mod/data/view.php?d=' . $data->id . '&amp;rid=' . $record->id;
  1232. if ($search) {
  1233. $moreurl .= '&amp;filter=1';
  1234. }
  1235. $patterns[]='##more##';
  1236. $replacement[] = '<a href="'.$moreurl.'">' . $OUTPUT->pix_icon('t/preview', get_string('more', 'data')) . '</a>';
  1237. $patterns[]='##moreurl##';
  1238. $replacement[] = $moreurl;
  1239. $patterns[]='##delcheck##';
  1240. if ($canmanageentries) {
  1241. $checkbox = new \core\output\checkbox_toggleall('listview-entries', false, [
  1242. 'id' => "entry_{$record->id}",
  1243. 'name' => 'delcheck[]',
  1244. 'classes' => 'recordcheckbox',
  1245. 'value' => $record->id,
  1246. ]);
  1247. $replacement[] = $OUTPUT->render($checkbox);
  1248. } else {
  1249. $replacement[] = '';
  1250. }
  1251. $patterns[]='##user##';
  1252. $replacement[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$record->userid.
  1253. '&amp;course='.$data->course.'">'.fullname($record).'</a>';
  1254. $patterns[] = '##userpicture##';
  1255. $ruser = user_picture::unalias($record, null, 'userid');
  1256. // If the record didn't come with user data, retrieve the user from database.
  1257. if (!isset($ruser->picture)) {
  1258. $ruser = core_user::get_user($record->userid);
  1259. }
  1260. $replacement[] = $OUTPUT->user_picture($ruser, array('courseid' => $data->course));
  1261. $patterns[]='##export##';
  1262. if (!empty($CFG->enableportfolios) && ($template == 'singletemplate' || $template == 'listtemplate')
  1263. && ((has_capability('mod/data:exportentry', $context)
  1264. || (data_isowner($record->id) && has_capability('mod/data:exportownentry', $context))))) {
  1265. require_once($CFG->libdir . '/portfoliolib.php');
  1266. $button = new portfolio_add_button();
  1267. $button->set_callback_options('data_portfolio_caller', array('id' => $cm->id, 'recordid' => $record->id), 'mod_data');
  1268. list($formats, $files) = data_portfolio_caller::formats($fields, $record);
  1269. $button->set_formats($formats);
  1270. $replacement[] = $button->to_html(PORTFOLIO_ADD_ICON_LINK);
  1271. } else {
  1272. $replacement[] = '';
  1273. }
  1274. $patterns[] = '##timeadded##';
  1275. $replacement[] = userdate($record->timecreated);
  1276. $patterns[] = '##timemodified##';
  1277. $replacement [] = userdate($record->timemodified);
  1278. $patterns[]='##approve##';
  1279. if (has_capability('mod/data:approve', $context) && ($data->approval) && (!$record->approved)) {
  1280. $approveurl = new moodle_url($jumpurl, array('approve' => $record->id));
  1281. $approveicon = new pix_icon('t/approve', get_string('approve', 'data'), '', array('class' => 'iconsmall'));
  1282. $replacement[] = html_writer::tag('span', $OUTPUT->action_icon($approveurl, $approveicon),
  1283. array('class' => 'approve'));
  1284. } else {
  1285. $replacement[] = '';
  1286. }
  1287. $patterns[]='##disapprove##';
  1288. if (has_capability('mod/data:approve', $context) && ($data->approval) && ($record->approved)) {
  1289. $disapproveurl = new moodle_url($jumpurl, array('disapprove' => $record->id));
  1290. $disapproveicon = new pix_icon('t/block', get_string('disapprove', 'data'), '', array('class' => 'iconsmall'));
  1291. $replacement[] = html_writer::tag('span', $OUTPUT->action_icon($disapproveurl, $disapproveicon),
  1292. array('class' => 'disapprove'));
  1293. } else {
  1294. $replacement[] = '';
  1295. }
  1296. $patterns[] = '##approvalstatus##';
  1297. $patterns[] = '##approvalstatusclass##';
  1298. if (!$data->approval) {
  1299. $replacement[] = '';
  1300. $replacement[] = '';
  1301. } else if ($record->approved) {
  1302. $replacement[] = get_string('approved', 'data');
  1303. $replacement[] = 'approved';
  1304. } else {
  1305. $replacement[] = get_string('notapproved', 'data');
  1306. $replacement[] = 'notapproved';
  1307. }
  1308. $patterns[]='##comments##';
  1309. if (($template == 'listtemplate') && ($data->comments)) {
  1310. if (!empty($CFG->usecomments)) {
  1311. require_once($CFG->dirroot . '/comment/lib.php');
  1312. list($context, $course, $cm) = get_context_info_array($context->id);
  1313. $cmt = new stdClass();
  1314. $cmt->context = $context;
  1315. $cmt->course = $course;
  1316. $cmt->cm = $cm;
  1317. $cmt->area = 'database_entry';
  1318. $cmt->itemid = $record->id;
  1319. $cmt->showcount = true;
  1320. $cmt->component = 'mod_data';
  1321. $comment = new comment($cmt);
  1322. $replacement[] = $comment->output(true);
  1323. }
  1324. } else {
  1325. $replacement[] = '';
  1326. }
  1327. if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
  1328. $patterns[] = "##tags##";
  1329. $replacement[] = $OUTPUT->tag_list(
  1330. core_tag_tag::get_item_tags('mod_data', 'data_records', $record->id), '', 'data-tags');
  1331. }
  1332. // actual replacement of the tags
  1333. $newtext = str_ireplace($patterns, $replacement, $data->{$template});
  1334. // no more html formatting and filtering - see MDL-6635
  1335. if ($return) {
  1336. return $newtext;
  1337. } else {
  1338. echo $newtext;
  1339. // hack alert - retu…

Large files files are truncated, but you can click here to view the full file