PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/mod/data/lib.php

http://github.com/moodle/moodle
PHP | 4828 lines | 3043 code | 601 blank | 1184 comment | 660 complexity | 55b7fcdc9afaa80ea57555bda39de997 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause

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

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