| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 4 | //
 | 
        
           |  |  | 5 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 6 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 7 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 8 | // (at your option) any later version.
 | 
        
           |  |  | 9 | //
 | 
        
           |  |  | 10 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 13 | // GNU General Public License for more details.
 | 
        
           |  |  | 14 | //
 | 
        
           |  |  | 15 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 16 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 17 |   | 
        
           |  |  | 18 | /**
 | 
        
           |  |  | 19 |  * @package   mod_data
 | 
        
           |  |  | 20 |  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
 | 
        
           |  |  | 21 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 | require_once($CFG->dirroot . '/mod/data/lib.php');
 | 
        
           |  |  | 27 | require_once($CFG->libdir . '/portfolio/caller.php');
 | 
        
           |  |  | 28 | require_once($CFG->libdir . '/filelib.php');
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | /**
 | 
        
           |  |  | 31 |  * The class to handle entry exports of a database module
 | 
        
           |  |  | 32 |  */
 | 
        
           |  |  | 33 | class data_portfolio_caller extends portfolio_module_caller_base {
 | 
        
           |  |  | 34 |   | 
        
           |  |  | 35 |     /** @var int the single record to export */
 | 
        
           |  |  | 36 |     protected $recordid;
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 |     /** @var object the record from the data table */
 | 
        
           |  |  | 39 |     private $data;
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 |     /**#@+ @var array the fields used and their fieldtypes */
 | 
        
           |  |  | 42 |     private $fields;
 | 
        
           |  |  | 43 |     private $fieldtypes;
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 |     /** @var object the records to export */
 | 
        
           |  |  | 46 |     private $records;
 | 
        
           |  |  | 47 |   | 
        
           |  |  | 48 |     /** @var int how many records are 'mine' */
 | 
        
           |  |  | 49 |     private $minecount;
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 |     /**
 | 
        
           |  |  | 52 |      * the required callback arguments for a single-record export
 | 
        
           |  |  | 53 |      *
 | 
        
           |  |  | 54 |      * @return array
 | 
        
           |  |  | 55 |      */
 | 
        
           |  |  | 56 |     public static function expected_callbackargs() {
 | 
        
           |  |  | 57 |         return array(
 | 
        
           |  |  | 58 |             'id'       => true,
 | 
        
           |  |  | 59 |             'recordid' => false,
 | 
        
           |  |  | 60 |         );
 | 
        
           |  |  | 61 |     }
 | 
        
           |  |  | 62 |   | 
        
           |  |  | 63 |     /**
 | 
        
           |  |  | 64 |      * @param array $callbackargs the arguments passed through
 | 
        
           |  |  | 65 |      */
 | 
        
           |  |  | 66 |     public function __construct($callbackargs) {
 | 
        
           |  |  | 67 |         parent::__construct($callbackargs);
 | 
        
           |  |  | 68 |     }
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 |     /**
 | 
        
           |  |  | 71 |      * load up the data needed for the export
 | 
        
           |  |  | 72 |      *
 | 
        
           |  |  | 73 |      * @global object $DB
 | 
        
           |  |  | 74 |      */
 | 
        
           |  |  | 75 |     public function load_data() {
 | 
        
           |  |  | 76 |         global $DB, $USER;
 | 
        
           |  |  | 77 |         if (!$this->cm = get_coursemodule_from_id('data', $this->id)) {
 | 
        
           |  |  | 78 |             throw new portfolio_caller_exception('invalidid', 'data');
 | 
        
           |  |  | 79 |         }
 | 
        
           |  |  | 80 |         if (!$this->data = $DB->get_record('data', array('id' => $this->cm->instance))) {
 | 
        
           |  |  | 81 |             throw new portfolio_caller_exception('invalidid', 'data');
 | 
        
           |  |  | 82 |         }
 | 
        
           |  |  | 83 |         $fieldrecords = $DB->get_records('data_fields', array('dataid' => $this->cm->instance), 'id');
 | 
        
           |  |  | 84 |         // populate objets for this databases fields
 | 
        
           |  |  | 85 |         $this->fields = array();
 | 
        
           |  |  | 86 |         foreach ($fieldrecords as $fieldrecord) {
 | 
        
           |  |  | 87 |             $tmp = data_get_field($fieldrecord, $this->data);
 | 
        
           |  |  | 88 |             $this->fields[] = $tmp;
 | 
        
           |  |  | 89 |             $this->fieldtypes[]  = $tmp->type;
 | 
        
           |  |  | 90 |         }
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |         $this->records = array();
 | 
        
           |  |  | 93 |         if ($this->recordid) {
 | 
        
           |  |  | 94 |             $tmp = $DB->get_record('data_records', array('id' => $this->recordid));
 | 
        
           |  |  | 95 |             $tmp->content = $DB->get_records('data_content', array('recordid' => $this->recordid));
 | 
        
           |  |  | 96 |             $this->records[] = $tmp;
 | 
        
           |  |  | 97 |         } else {
 | 
        
           |  |  | 98 |             $where = array('dataid' => $this->data->id);
 | 
        
           |  |  | 99 |             if (!has_capability('mod/data:exportallentries', context_module::instance($this->cm->id))) {
 | 
        
           |  |  | 100 |                 $where['userid'] = $USER->id; // get them all in case, we'll unset ones that aren't ours later if necessary
 | 
        
           |  |  | 101 |             }
 | 
        
           |  |  | 102 |             $tmp = $DB->get_records('data_records', $where);
 | 
        
           |  |  | 103 |             foreach ($tmp as $t) {
 | 
        
           |  |  | 104 |                 $t->content = $DB->get_records('data_content', array('recordid' => $t->id));
 | 
        
           |  |  | 105 |                 $this->records[] = $t;
 | 
        
           |  |  | 106 |             }
 | 
        
           |  |  | 107 |             $this->minecount = $DB->count_records('data_records', array('dataid' => $this->data->id, 'userid' => $USER->id));
 | 
        
           |  |  | 108 |         }
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |         if ($this->recordid) {
 | 
        
           |  |  | 111 |             list($formats, $files) = self::formats($this->fields, $this->records[0]);
 | 
        
           |  |  | 112 |             $this->set_file_and_format_data($files);
 | 
        
           |  |  | 113 |         }
 | 
        
           |  |  | 114 |     }
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |     /**
 | 
        
           |  |  | 117 |      * How long we think the export will take
 | 
        
           |  |  | 118 |      * Single entry is probably not too long.
 | 
        
           |  |  | 119 |      * But we check for filesizes
 | 
        
           |  |  | 120 |      * Else base it on the number of records
 | 
        
           |  |  | 121 |      *
 | 
        
           |  |  | 122 |      * @return one of PORTFOLIO_TIME_XX constants
 | 
        
           |  |  | 123 |      */
 | 
        
           |  |  | 124 |     public function expected_time() {
 | 
        
           |  |  | 125 |         if ($this->recordid) {
 | 
        
           |  |  | 126 |             return $this->expected_time_file();
 | 
        
           |  |  | 127 |         } else {
 | 
        
           |  |  | 128 |             return portfolio_expected_time_db(count($this->records));
 | 
        
           |  |  | 129 |         }
 | 
        
           |  |  | 130 |     }
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |     /**
 | 
        
           |  |  | 133 |      * Calculate the shal1 of this export
 | 
        
           |  |  | 134 |      * Dependent on the export format.
 | 
        
           |  |  | 135 |      * @return string
 | 
        
           |  |  | 136 |      */
 | 
        
           |  |  | 137 |     public function get_sha1() {
 | 
        
           |  |  | 138 |         // in the case that we're exporting a subclass of 'file' and we have a singlefile,
 | 
        
           |  |  | 139 |         // then we're not exporting any metadata, just the file by itself by mimetype.
 | 
        
           |  |  | 140 |         if ($this->exporter->get('format') instanceof portfolio_format_file && $this->singlefile) {
 | 
        
           |  |  | 141 |             return $this->get_sha1_file();
 | 
        
           |  |  | 142 |         }
 | 
        
           |  |  | 143 |         // otherwise we're exporting some sort of multipart content so use the data
 | 
        
           |  |  | 144 |         $str = '';
 | 
        
           |  |  | 145 |         foreach ($this->records as $record) {
 | 
        
           |  |  | 146 |             foreach ($record as $data) {
 | 
        
           |  |  | 147 |                 if (is_array($data) || is_object($data)) {
 | 
        
           |  |  | 148 |                     $keys = array_keys($data);
 | 
        
           |  |  | 149 |                     $testkey = array_pop($keys);
 | 
        
           |  |  | 150 |                     if (is_array($data[$testkey]) || is_object($data[$testkey])) {
 | 
        
           |  |  | 151 |                         foreach ($data as $d) {
 | 
        
           |  |  | 152 |                             $str .= implode(',', (array)$d);
 | 
        
           |  |  | 153 |                         }
 | 
        
           |  |  | 154 |                     } else {
 | 
        
           |  |  | 155 |                         $str .= implode(',', (array)$data);
 | 
        
           |  |  | 156 |                     }
 | 
        
           |  |  | 157 |                 } else {
 | 
        
           |  |  | 158 |                     $str .= $data;
 | 
        
           |  |  | 159 |                 }
 | 
        
           |  |  | 160 |             }
 | 
        
           |  |  | 161 |         }
 | 
        
           |  |  | 162 |         return sha1($str . ',' . $this->exporter->get('formatclass'));
 | 
        
           |  |  | 163 |     }
 | 
        
           |  |  | 164 |   | 
        
           |  |  | 165 |     /**
 | 
        
           |  |  | 166 |      * Prepare the package for export
 | 
        
           |  |  | 167 |      *
 | 
        
           |  |  | 168 |      * @return stored_file object
 | 
        
           |  |  | 169 |      */
 | 
        
           |  |  | 170 |     public function prepare_package() {
 | 
        
           |  |  | 171 |         global $DB;
 | 
        
           |  |  | 172 |         $leapwriter = null;
 | 
        
           |  |  | 173 |         $content = '';
 | 
        
           |  |  | 174 |         $filename = '';
 | 
        
           |  |  | 175 |         $uid = $this->exporter->get('user')->id;
 | 
        
           |  |  | 176 |         $users = array(); //cache
 | 
        
           |  |  | 177 |         $onlymine = $this->get_export_config('mineonly');
 | 
        
           |  |  | 178 |         if ($this->exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
 | 
        
           |  |  | 179 |             $leapwriter = $this->exporter->get('format')->leap2a_writer();
 | 
        
           |  |  | 180 |             $ids = array();
 | 
        
           |  |  | 181 |         }
 | 
        
           |  |  | 182 |   | 
        
           |  |  | 183 |         if ($this->exporter->get('format') instanceof portfolio_format_file && $this->singlefile) {
 | 
        
           |  |  | 184 |             return $this->get('exporter')->copy_existing_file($this->singlefile);
 | 
        
           |  |  | 185 |         }
 | 
        
           |  |  | 186 |         foreach ($this->records  as $key => $record) {
 | 
        
           |  |  | 187 |             if ($onlymine && $record->userid != $uid) {
 | 
        
           |  |  | 188 |                 unset($this->records[$key]); // sha1
 | 
        
           |  |  | 189 |                 continue;
 | 
        
           |  |  | 190 |             }
 | 
        
           |  |  | 191 |             list($tmpcontent, $files)  = $this->exportentry($record);
 | 
        
           |  |  | 192 |             $content .= $tmpcontent;
 | 
        
           |  |  | 193 |             if ($leapwriter) {
 | 
        
           |  |  | 194 |                 $entry = new portfolio_format_leap2a_entry('dataentry' . $record->id, $this->data->name, 'resource', $tmpcontent);
 | 
        
           |  |  | 195 |                 $entry->published = $record->timecreated;
 | 
        
           |  |  | 196 |                 $entry->updated = $record->timemodified;
 | 
        
           |  |  | 197 |                 if ($record->userid != $uid) {
 | 
        
           |  |  | 198 |                     if (!array_key_exists($record->userid, $users)) {
 | 
        
           |  |  | 199 |                         $users[$record->userid] = $DB->get_record('user', array('id' => $record->userid), 'id,firstname,lastname');
 | 
        
           |  |  | 200 |                     }
 | 
        
           |  |  | 201 |                     $entry->author = $users[$record->userid];
 | 
        
           |  |  | 202 |                 }
 | 
        
           |  |  | 203 |                 $ids[] = $entry->id;
 | 
        
           |  |  | 204 |                 $leapwriter->link_files($entry, $files, 'dataentry' . $record->id . 'file');
 | 
        
           |  |  | 205 |                 $leapwriter->add_entry($entry);
 | 
        
           |  |  | 206 |             }
 | 
        
           |  |  | 207 |         }
 | 
        
           |  |  | 208 |         if ($leapwriter) {
 | 
        
           |  |  | 209 |             if (count($this->records) > 1) { // make a selection element to tie them all together
 | 
        
           |  |  | 210 |                 $selection = new portfolio_format_leap2a_entry('datadb' . $this->data->id,
 | 
        
           |  |  | 211 |                     get_string('entries', 'data') . ': ' . $this->data->name, 'selection');
 | 
        
           |  |  | 212 |                 $leapwriter->add_entry($selection);
 | 
        
           |  |  | 213 |                 $leapwriter->make_selection($selection, $ids, 'Grouping');
 | 
        
           |  |  | 214 |             }
 | 
        
           |  |  | 215 |             $filename = $this->exporter->get('format')->manifest_name();
 | 
        
           |  |  | 216 |             $content = $leapwriter->to_xml();
 | 
        
           |  |  | 217 |         } else {
 | 
        
           |  |  | 218 |             if (count($this->records) == 1) {
 | 
        
           |  |  | 219 |                 $filename = clean_filename($this->cm->name . '-entry.html');
 | 
        
           |  |  | 220 |             } else {
 | 
        
           |  |  | 221 |                 $filename = clean_filename($this->cm->name . '-full.html');
 | 
        
           |  |  | 222 |             }
 | 
        
           |  |  | 223 |         }
 | 
        
           |  |  | 224 |         return $this->exporter->write_new_file(
 | 
        
           |  |  | 225 |             $content,
 | 
        
           |  |  | 226 |             $filename,
 | 
        
           |  |  | 227 |             ($this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH) // if we have associate files, this is a 'manifest'
 | 
        
           |  |  | 228 |         );
 | 
        
           |  |  | 229 |     }
 | 
        
           |  |  | 230 |   | 
        
           |  |  | 231 |     /**
 | 
        
           |  |  | 232 |      * Verify the user can still export this entry
 | 
        
           |  |  | 233 |      *
 | 
        
           |  |  | 234 |      * @return bool
 | 
        
           |  |  | 235 |      */
 | 
        
           |  |  | 236 |     public function check_permissions() {
 | 
        
           |  |  | 237 |         if ($this->recordid) {
 | 
        
           |  |  | 238 |             if (data_isowner($this->recordid)) {
 | 
        
           |  |  | 239 |                 return has_capability('mod/data:exportownentry', context_module::instance($this->cm->id));
 | 
        
           |  |  | 240 |             }
 | 
        
           |  |  | 241 |             return has_capability('mod/data:exportentry', context_module::instance($this->cm->id));
 | 
        
           |  |  | 242 |         }
 | 
        
           |  |  | 243 |         if ($this->has_export_config() && !$this->get_export_config('mineonly')) {
 | 
        
           |  |  | 244 |             return has_capability('mod/data:exportallentries', context_module::instance($this->cm->id));
 | 
        
           |  |  | 245 |         }
 | 
        
           |  |  | 246 |         return has_capability('mod/data:exportownentry', context_module::instance($this->cm->id));
 | 
        
           |  |  | 247 |     }
 | 
        
           |  |  | 248 |   | 
        
           |  |  | 249 |     /**
 | 
        
           |  |  | 250 |      *  @return string
 | 
        
           |  |  | 251 |      */
 | 
        
           |  |  | 252 |     public static function display_name() {
 | 
        
           |  |  | 253 |         return get_string('modulename', 'data');
 | 
        
           |  |  | 254 |     }
 | 
        
           |  |  | 255 |   | 
        
           |  |  | 256 |     /**
 | 
        
           |  |  | 257 |      * @global object
 | 
        
           |  |  | 258 |      * @return bool|void
 | 
        
           |  |  | 259 |      */
 | 
        
           |  |  | 260 |     public function __wakeup() {
 | 
        
           |  |  | 261 |         global $CFG;
 | 
        
           |  |  | 262 |         if (empty($CFG)) {
 | 
        
           |  |  | 263 |             return true; // too early yet
 | 
        
           |  |  | 264 |         }
 | 
        
           |  |  | 265 |         foreach ($this->fieldtypes as $key => $field) {
 | 
        
           |  |  | 266 |             $filepath = $CFG->dirroot . '/mod/data/field/' . $field .'/field.class.php';
 | 
        
           |  |  | 267 |             if (!file_exists($filepath)) {
 | 
        
           |  |  | 268 |                 continue;
 | 
        
           |  |  | 269 |             }
 | 
        
           |  |  | 270 |             require_once($filepath);
 | 
        
           |  |  | 271 |             $this->fields[$key] = unserialize(serialize($this->fields[$key]));
 | 
        
           |  |  | 272 |         }
 | 
        
           |  |  | 273 |     }
 | 
        
           |  |  | 274 |   | 
        
           |  |  | 275 |     /**
 | 
        
           |  |  | 276 |      * Prepare a single entry for export, replacing all the content etc
 | 
        
           |  |  | 277 |      *
 | 
        
           |  |  | 278 |      * @param stdclass $record the entry to export
 | 
        
           |  |  | 279 |      *
 | 
        
           |  |  | 280 |      * @return array with key 0 = the html content, key 1 = array of attachments
 | 
        
           |  |  | 281 |      */
 | 
        
           |  |  | 282 |     private function exportentry($record) {
 | 
        
           |  |  | 283 |     // Replacing tags
 | 
        
           |  |  | 284 |         $patterns = array();
 | 
        
           |  |  | 285 |         $replacement = array();
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |         $files = array();
 | 
        
           |  |  | 288 |     // Then we generate strings to replace for normal tags
 | 
        
           |  |  | 289 |         $format = $this->get('exporter')->get('format');
 | 
        
           |  |  | 290 |         foreach ($this->fields as $field) {
 | 
        
           |  |  | 291 |             $patterns[]='[['.$field->field->name.']]';
 | 
        
           |  |  | 292 |             if (is_callable(array($field, 'get_file'))) {
 | 
        
           |  |  | 293 |                 if (!$file = $field->get_file($record->id)) {
 | 
        
           |  |  | 294 |                     $replacement[] = '';
 | 
        
           |  |  | 295 |                     continue; // probably left empty
 | 
        
           |  |  | 296 |                 }
 | 
        
           |  |  | 297 |                 $replacement[] = $format->file_output($file);
 | 
        
           |  |  | 298 |                 $this->get('exporter')->copy_existing_file($file);
 | 
        
           |  |  | 299 |                 $files[] = $file;
 | 
        
           |  |  | 300 |             } else {
 | 
        
           |  |  | 301 |                 $replacement[] = $field->display_browse_field($record->id, 'singletemplate');
 | 
        
           |  |  | 302 |             }
 | 
        
           |  |  | 303 |         }
 | 
        
           |  |  | 304 |   | 
        
           |  |  | 305 |     // Replacing special tags (##Edit##, ##Delete##, ##More##)
 | 
        
           |  |  | 306 |         $patterns[]='##edit##';
 | 
        
           |  |  | 307 |         $patterns[]='##delete##';
 | 
        
           |  |  | 308 |         $patterns[]='##export##';
 | 
        
           |  |  | 309 |         $patterns[]='##more##';
 | 
        
           |  |  | 310 |         $patterns[]='##moreurl##';
 | 
        
           |  |  | 311 |         $patterns[]='##user##';
 | 
        
           |  |  | 312 |         $patterns[]='##approve##';
 | 
        
           |  |  | 313 |         $patterns[]='##disapprove##';
 | 
        
           |  |  | 314 |         $patterns[]='##comments##';
 | 
        
           |  |  | 315 |         $patterns[] = '##timeadded##';
 | 
        
           |  |  | 316 |         $patterns[] = '##timemodified##';
 | 
        
           |  |  | 317 |         $replacement[] = '';
 | 
        
           |  |  | 318 |         $replacement[] = '';
 | 
        
           |  |  | 319 |         $replacement[] = '';
 | 
        
           |  |  | 320 |         $replacement[] = '';
 | 
        
           |  |  | 321 |         $replacement[] = '';
 | 
        
           |  |  | 322 |         $replacement[] = '';
 | 
        
           |  |  | 323 |         $replacement[] = '';
 | 
        
           |  |  | 324 |         $replacement[] = '';
 | 
        
           |  |  | 325 |         $replacement[] = '';
 | 
        
           |  |  | 326 |         $replacement[] = userdate($record->timecreated);
 | 
        
           |  |  | 327 |         $replacement[] = userdate($record->timemodified);
 | 
        
           |  |  | 328 |   | 
        
           |  |  | 329 |         if (empty($this->data->singletemplate)) {
 | 
        
           |  |  | 330 |             // Use default template if the template is not created.
 | 
        
           |  |  | 331 |             $this->data->singletemplate = data_generate_default_template($this->data, 'singletemplate', 0, false, false);
 | 
        
           |  |  | 332 |         }
 | 
        
           |  |  | 333 |   | 
        
           |  |  | 334 |         // actual replacement of the tags
 | 
        
           |  |  | 335 |         return array(str_ireplace($patterns, $replacement, $this->data->singletemplate), $files);
 | 
        
           |  |  | 336 |     }
 | 
        
           |  |  | 337 |   | 
        
           |  |  | 338 |     /**
 | 
        
           |  |  | 339 |      * Given the fields being exported, and the single record,
 | 
        
           |  |  | 340 |      * work out which export format(s) we can use
 | 
        
           |  |  | 341 |      *
 | 
        
           |  |  | 342 |      * @param array $fields array of field objects
 | 
        
           |  |  | 343 |      * @param object $record The data record object
 | 
        
           |  |  | 344 |      *
 | 
        
           |  |  | 345 |      * @uses PORTFOLIO_FORMAT_PLAINHTML
 | 
        
           |  |  | 346 |      * @uses PORTFOLIO_FORMAT_RICHHTML
 | 
        
           |  |  | 347 |      *
 | 
        
           |  |  | 348 |      * @return array of PORTFOLIO_XX constants
 | 
        
           |  |  | 349 |      */
 | 
        
           |  |  | 350 |     public static function formats($fields, $record) {
 | 
        
           |  |  | 351 |         $formats = array(PORTFOLIO_FORMAT_PLAINHTML);
 | 
        
           |  |  | 352 |         $includedfiles = array();
 | 
        
           |  |  | 353 |         foreach ($fields as $singlefield) {
 | 
        
           |  |  | 354 |             if (is_callable(array($singlefield, 'get_file'))) {
 | 
        
           |  |  | 355 |                 if ($file = $singlefield->get_file($record->id)) {
 | 
        
           |  |  | 356 |                     $includedfiles[] = $file;
 | 
        
           |  |  | 357 |                 }
 | 
        
           |  |  | 358 |             }
 | 
        
           |  |  | 359 |         }
 | 
        
           |  |  | 360 |         if (count($includedfiles) == 1 && count($fields) == 1) {
 | 
        
           |  |  | 361 |             $formats = array(portfolio_format_from_mimetype($includedfiles[0]->get_mimetype()));
 | 
        
           |  |  | 362 |         } else if (count($includedfiles) > 0) {
 | 
        
           |  |  | 363 |             $formats = array(PORTFOLIO_FORMAT_RICHHTML);
 | 
        
           |  |  | 364 |         }
 | 
        
           |  |  | 365 |         return array($formats, $includedfiles);
 | 
        
           |  |  | 366 |     }
 | 
        
           |  |  | 367 |   | 
        
           |  |  | 368 |     public static function has_files($data) {
 | 
        
           |  |  | 369 |         global $DB;
 | 
        
           |  |  | 370 |         $fieldrecords = $DB->get_records('data_fields', array('dataid' => $data->id), 'id');
 | 
        
           |  |  | 371 |         // populate objets for this databases fields
 | 
        
           |  |  | 372 |         foreach ($fieldrecords as $fieldrecord) {
 | 
        
           |  |  | 373 |             $field = data_get_field($fieldrecord, $data);
 | 
        
           |  |  | 374 |             if (is_callable(array($field, 'get_file'))) {
 | 
        
           |  |  | 375 |                 return true;
 | 
        
           |  |  | 376 |             }
 | 
        
           |  |  | 377 |         }
 | 
        
           |  |  | 378 |         return false;
 | 
        
           |  |  | 379 |     }
 | 
        
           |  |  | 380 |   | 
        
           |  |  | 381 |     /**
 | 
        
           |  |  | 382 |      * base supported formats before we know anything about the export
 | 
        
           |  |  | 383 |      */
 | 
        
           |  |  | 384 |     public static function base_supported_formats() {
 | 
        
           |  |  | 385 |         return array(PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_LEAP2A);
 | 
        
           |  |  | 386 |     }
 | 
        
           |  |  | 387 |   | 
        
           |  |  | 388 |     public function has_export_config() {
 | 
        
           |  |  | 389 |         // if we're exporting more than just a single entry,
 | 
        
           |  |  | 390 |         // and we have the capability to export all entries,
 | 
        
           |  |  | 391 |         // then ask whether we want just our own, or all of them
 | 
        
           |  |  | 392 |         return (empty($this->recordid) // multi-entry export
 | 
        
           |  |  | 393 |             && $this->minecount > 0    // some of them are mine
 | 
        
           |  |  | 394 |             && $this->minecount != count($this->records) // not all of them are mine
 | 
        
           |  |  | 395 |             && has_capability('mod/data:exportallentries', context_module::instance($this->cm->id))); // they actually have a choice in the matter
 | 
        
           |  |  | 396 |     }
 | 
        
           |  |  | 397 |   | 
        
           |  |  | 398 |     public function export_config_form(&$mform, $instance) {
 | 
        
           |  |  | 399 |         if (!$this->has_export_config()) {
 | 
        
           |  |  | 400 |             return;
 | 
        
           |  |  | 401 |         }
 | 
        
           |  |  | 402 |         $mform->addElement('selectyesno', 'mineonly', get_string('exportownentries', 'data', (object)array('mine' => $this->minecount, 'all' => count($this->records))));
 | 
        
           |  |  | 403 |         $mform->setDefault('mineonly', 1);
 | 
        
           |  |  | 404 |     }
 | 
        
           |  |  | 405 |   | 
        
           |  |  | 406 |     public function get_allowed_export_config() {
 | 
        
           |  |  | 407 |         return array('mineonly');
 | 
        
           |  |  | 408 |     }
 | 
        
           |  |  | 409 | }
 | 
        
           |  |  | 410 |   | 
        
           |  |  | 411 |   | 
        
           |  |  | 412 | /**
 | 
        
           |  |  | 413 |  * Class representing the virtual node with all itemids in the file browser
 | 
        
           |  |  | 414 |  *
 | 
        
           |  |  | 415 |  * @category  files
 | 
        
           |  |  | 416 |  * @copyright 2012 David Mudrak <david@moodle.com>
 | 
        
           |  |  | 417 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 418 |  */
 | 
        
           |  |  | 419 | class data_file_info_container extends file_info {
 | 
        
           |  |  | 420 |     /** @var file_browser */
 | 
        
           |  |  | 421 |     protected $browser;
 | 
        
           |  |  | 422 |     /** @var stdClass */
 | 
        
           |  |  | 423 |     protected $course;
 | 
        
           |  |  | 424 |     /** @var stdClass */
 | 
        
           |  |  | 425 |     protected $cm;
 | 
        
           |  |  | 426 |     /** @var string */
 | 
        
           |  |  | 427 |     protected $component;
 | 
        
           |  |  | 428 |     /** @var stdClass */
 | 
        
           |  |  | 429 |     protected $context;
 | 
        
           |  |  | 430 |     /** @var array */
 | 
        
           |  |  | 431 |     protected $areas;
 | 
        
           |  |  | 432 |     /** @var string */
 | 
        
           |  |  | 433 |     protected $filearea;
 | 
        
           |  |  | 434 |   | 
        
           |  |  | 435 |     /**
 | 
        
           |  |  | 436 |      * Constructor (in case you did not realize it ;-)
 | 
        
           |  |  | 437 |      *
 | 
        
           |  |  | 438 |      * @param file_browser $browser
 | 
        
           |  |  | 439 |      * @param stdClass $course
 | 
        
           |  |  | 440 |      * @param stdClass $cm
 | 
        
           |  |  | 441 |      * @param stdClass $context
 | 
        
           |  |  | 442 |      * @param array $areas
 | 
        
           |  |  | 443 |      * @param string $filearea
 | 
        
           |  |  | 444 |      */
 | 
        
           |  |  | 445 |     public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
 | 
        
           |  |  | 446 |         parent::__construct($browser, $context);
 | 
        
           |  |  | 447 |         $this->browser = $browser;
 | 
        
           |  |  | 448 |         $this->course = $course;
 | 
        
           |  |  | 449 |         $this->cm = $cm;
 | 
        
           |  |  | 450 |         $this->component = 'mod_data';
 | 
        
           |  |  | 451 |         $this->context = $context;
 | 
        
           |  |  | 452 |         $this->areas = $areas;
 | 
        
           |  |  | 453 |         $this->filearea = $filearea;
 | 
        
           |  |  | 454 |     }
 | 
        
           |  |  | 455 |   | 
        
           |  |  | 456 |     /**
 | 
        
           |  |  | 457 |      * @return array with keys contextid, filearea, itemid, filepath and filename
 | 
        
           |  |  | 458 |      */
 | 
        
           |  |  | 459 |     public function get_params() {
 | 
        
           |  |  | 460 |         return array(
 | 
        
           |  |  | 461 |             'contextid' => $this->context->id,
 | 
        
           |  |  | 462 |             'component' => $this->component,
 | 
        
           |  |  | 463 |             'filearea' => $this->filearea,
 | 
        
           |  |  | 464 |             'itemid' => null,
 | 
        
           |  |  | 465 |             'filepath' => null,
 | 
        
           |  |  | 466 |             'filename' => null,
 | 
        
           |  |  | 467 |         );
 | 
        
           |  |  | 468 |     }
 | 
        
           |  |  | 469 |   | 
        
           |  |  | 470 |     /**
 | 
        
           |  |  | 471 |      * Can new files or directories be added via the file browser
 | 
        
           |  |  | 472 |      *
 | 
        
           |  |  | 473 |      * @return bool
 | 
        
           |  |  | 474 |      */
 | 
        
           |  |  | 475 |     public function is_writable() {
 | 
        
           |  |  | 476 |         return false;
 | 
        
           |  |  | 477 |     }
 | 
        
           |  |  | 478 |   | 
        
           |  |  | 479 |     /**
 | 
        
           |  |  | 480 |      * Should this node be considered as a folder in the file browser
 | 
        
           |  |  | 481 |      *
 | 
        
           |  |  | 482 |      * @return bool
 | 
        
           |  |  | 483 |      */
 | 
        
           |  |  | 484 |     public function is_directory() {
 | 
        
           |  |  | 485 |         return true;
 | 
        
           |  |  | 486 |     }
 | 
        
           |  |  | 487 |   | 
        
           |  |  | 488 |     /**
 | 
        
           |  |  | 489 |      * Returns localised visible name of this node
 | 
        
           |  |  | 490 |      *
 | 
        
           |  |  | 491 |      * @return string
 | 
        
           |  |  | 492 |      */
 | 
        
           |  |  | 493 |     public function get_visible_name() {
 | 
        
           |  |  | 494 |         return $this->areas[$this->filearea];
 | 
        
           |  |  | 495 |     }
 | 
        
           |  |  | 496 |   | 
        
           |  |  | 497 |     /**
 | 
        
           |  |  | 498 |      * Returns list of children nodes
 | 
        
           |  |  | 499 |      *
 | 
        
           |  |  | 500 |      * @return array of file_info instances
 | 
        
           |  |  | 501 |      */
 | 
        
           |  |  | 502 |     public function get_children() {
 | 
        
           |  |  | 503 |         return $this->get_filtered_children('*', false, true);
 | 
        
           |  |  | 504 |     }
 | 
        
           |  |  | 505 |   | 
        
           |  |  | 506 |     /**
 | 
        
           |  |  | 507 |      * Help function to return files matching extensions or their count
 | 
        
           |  |  | 508 |      *
 | 
        
           |  |  | 509 |      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 | 
        
           |  |  | 510 |      * @param bool|int $countonly if false returns the children, if an int returns just the
 | 
        
           |  |  | 511 |      *    count of children but stops counting when $countonly number of children is reached
 | 
        
           |  |  | 512 |      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
 | 
        
           |  |  | 513 |      * @return array|int array of file_info instances or the count
 | 
        
           |  |  | 514 |      */
 | 
        
           |  |  | 515 |     private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
 | 
        
           |  |  | 516 |         global $DB;
 | 
        
           |  |  | 517 |         $params = array('contextid' => $this->context->id,
 | 
        
           |  |  | 518 |             'component' => $this->component,
 | 
        
           |  |  | 519 |             'filearea' => $this->filearea);
 | 
        
           |  |  | 520 |         $sql = 'SELECT DISTINCT itemid
 | 
        
           |  |  | 521 |                     FROM {files}
 | 
        
           |  |  | 522 |                     WHERE contextid = :contextid
 | 
        
           |  |  | 523 |                     AND component = :component
 | 
        
           |  |  | 524 |                     AND filearea = :filearea';
 | 
        
           |  |  | 525 |         if (!$returnemptyfolders) {
 | 
        
           |  |  | 526 |             $sql .= ' AND filename <> :emptyfilename';
 | 
        
           |  |  | 527 |             $params['emptyfilename'] = '.';
 | 
        
           |  |  | 528 |         }
 | 
        
           |  |  | 529 |         list($sql2, $params2) = $this->build_search_files_sql($extensions);
 | 
        
           |  |  | 530 |         $sql .= ' '.$sql2;
 | 
        
           |  |  | 531 |         $params = array_merge($params, $params2);
 | 
        
           |  |  | 532 |         if ($countonly === false) {
 | 
        
           |  |  | 533 |             $sql .= ' ORDER BY itemid DESC';
 | 
        
           |  |  | 534 |         }
 | 
        
           |  |  | 535 |   | 
        
           |  |  | 536 |         $rs = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 537 |         $children = array();
 | 
        
           |  |  | 538 |         foreach ($rs as $record) {
 | 
        
           |  |  | 539 |             if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $record->itemid)) {
 | 
        
           |  |  | 540 |                 $children[] = $child;
 | 
        
           |  |  | 541 |             }
 | 
        
           |  |  | 542 |             if ($countonly !== false && count($children) >= $countonly) {
 | 
        
           |  |  | 543 |                 break;
 | 
        
           |  |  | 544 |             }
 | 
        
           |  |  | 545 |         }
 | 
        
           |  |  | 546 |         $rs->close();
 | 
        
           |  |  | 547 |         if ($countonly !== false) {
 | 
        
           |  |  | 548 |             return count($children);
 | 
        
           |  |  | 549 |         }
 | 
        
           |  |  | 550 |         return $children;
 | 
        
           |  |  | 551 |     }
 | 
        
           |  |  | 552 |   | 
        
           |  |  | 553 |     /**
 | 
        
           |  |  | 554 |      * Returns list of children which are either files matching the specified extensions
 | 
        
           |  |  | 555 |      * or folders that contain at least one such file.
 | 
        
           |  |  | 556 |      *
 | 
        
           |  |  | 557 |      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 | 
        
           |  |  | 558 |      * @return array of file_info instances
 | 
        
           |  |  | 559 |      */
 | 
        
           |  |  | 560 |     public function get_non_empty_children($extensions = '*') {
 | 
        
           |  |  | 561 |         return $this->get_filtered_children($extensions, false);
 | 
        
           |  |  | 562 |     }
 | 
        
           |  |  | 563 |   | 
        
           |  |  | 564 |     /**
 | 
        
           |  |  | 565 |      * Returns the number of children which are either files matching the specified extensions
 | 
        
           |  |  | 566 |      * or folders containing at least one such file.
 | 
        
           |  |  | 567 |      *
 | 
        
           |  |  | 568 |      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
 | 
        
           |  |  | 569 |      * @param int $limit stop counting after at least $limit non-empty children are found
 | 
        
           |  |  | 570 |      * @return int
 | 
        
           |  |  | 571 |      */
 | 
        
           |  |  | 572 |     public function count_non_empty_children($extensions = '*', $limit = 1) {
 | 
        
           |  |  | 573 |         return $this->get_filtered_children($extensions, $limit);
 | 
        
           |  |  | 574 |     }
 | 
        
           |  |  | 575 |   | 
        
           |  |  | 576 |     /**
 | 
        
           |  |  | 577 |      * Returns parent file_info instance
 | 
        
           |  |  | 578 |      *
 | 
        
           |  |  | 579 |      * @return file_info or null for root
 | 
        
           |  |  | 580 |      */
 | 
        
           |  |  | 581 |     public function get_parent() {
 | 
        
           |  |  | 582 |         return $this->browser->get_file_info($this->context);
 | 
        
           |  |  | 583 |     }
 | 
        
           |  |  | 584 | }
 | 
        
           |  |  | 585 |   | 
        
           |  |  | 586 | /**
 | 
        
           |  |  | 587 |  * This creates new calendar events given as timeavailablefrom and timeclose by $data.
 | 
        
           |  |  | 588 |  *
 | 
        
           |  |  | 589 |  * @param stdClass $data
 | 
        
           |  |  | 590 |  * @return void
 | 
        
           |  |  | 591 |  */
 | 
        
           |  |  | 592 | function data_set_events($data) {
 | 
        
           |  |  | 593 |     global $DB, $CFG;
 | 
        
           |  |  | 594 |   | 
        
           |  |  | 595 |     require_once($CFG->dirroot.'/calendar/lib.php');
 | 
        
           |  |  | 596 |   | 
        
           |  |  | 597 |     // Get CMID if not sent as part of $data.
 | 
        
           |  |  | 598 |     if (!isset($data->coursemodule)) {
 | 
        
           |  |  | 599 |         $cm = get_coursemodule_from_instance('data', $data->id, $data->course);
 | 
        
           |  |  | 600 |         $data->coursemodule = $cm->id;
 | 
        
           |  |  | 601 |     }
 | 
        
           |  |  | 602 |     // Data start calendar events.
 | 
        
           |  |  | 603 |     $event = new stdClass();
 | 
        
           |  |  | 604 |     $event->eventtype = DATA_EVENT_TYPE_OPEN;
 | 
        
           |  |  | 605 |     // The DATA_EVENT_TYPE_OPEN event should only be an action event if no close time was specified.
 | 
        
           |  |  | 606 |     $event->type = empty($data->timeavailableto) ? CALENDAR_EVENT_TYPE_ACTION : CALENDAR_EVENT_TYPE_STANDARD;
 | 
        
           |  |  | 607 |     if ($event->id = $DB->get_field('event', 'id',
 | 
        
           |  |  | 608 |             array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => $event->eventtype))) {
 | 
        
           |  |  | 609 |         if ($data->timeavailablefrom > 0) {
 | 
        
           |  |  | 610 |             // Calendar event exists so update it.
 | 
        
           |  |  | 611 |             $event->name         = get_string('calendarstart', 'data', $data->name);
 | 
        
           |  |  | 612 |             $event->description  = format_module_intro('data', $data, $data->coursemodule, false);
 | 
        
           |  |  | 613 |             $event->format       = FORMAT_HTML;
 | 
        
           |  |  | 614 |             $event->timestart    = $data->timeavailablefrom;
 | 
        
           |  |  | 615 |             $event->timesort     = $data->timeavailablefrom;
 | 
        
           |  |  | 616 |             $event->visible      = instance_is_visible('data', $data);
 | 
        
           |  |  | 617 |             $event->timeduration = 0;
 | 
        
           |  |  | 618 |             $calendarevent = calendar_event::load($event->id);
 | 
        
           |  |  | 619 |             $calendarevent->update($event, false);
 | 
        
           |  |  | 620 |         } else {
 | 
        
           |  |  | 621 |             // Calendar event is on longer needed.
 | 
        
           |  |  | 622 |             $calendarevent = calendar_event::load($event->id);
 | 
        
           |  |  | 623 |             $calendarevent->delete();
 | 
        
           |  |  | 624 |         }
 | 
        
           |  |  | 625 |     } else {
 | 
        
           |  |  | 626 |         // Event doesn't exist so create one.
 | 
        
           |  |  | 627 |         if (isset($data->timeavailablefrom) && $data->timeavailablefrom > 0) {
 | 
        
           |  |  | 628 |             $event->name         = get_string('calendarstart', 'data', $data->name);
 | 
        
           |  |  | 629 |             $event->description  = format_module_intro('data', $data, $data->coursemodule, false);
 | 
        
           |  |  | 630 |             $event->format       = FORMAT_HTML;
 | 
        
           |  |  | 631 |             $event->courseid     = $data->course;
 | 
        
           |  |  | 632 |             $event->groupid      = 0;
 | 
        
           |  |  | 633 |             $event->userid       = 0;
 | 
        
           |  |  | 634 |             $event->modulename   = 'data';
 | 
        
           |  |  | 635 |             $event->instance     = $data->id;
 | 
        
           |  |  | 636 |             $event->timestart    = $data->timeavailablefrom;
 | 
        
           |  |  | 637 |             $event->timesort     = $data->timeavailablefrom;
 | 
        
           |  |  | 638 |             $event->visible      = instance_is_visible('data', $data);
 | 
        
           |  |  | 639 |             $event->timeduration = 0;
 | 
        
           |  |  | 640 |             calendar_event::create($event, false);
 | 
        
           |  |  | 641 |         }
 | 
        
           |  |  | 642 |     }
 | 
        
           |  |  | 643 |   | 
        
           |  |  | 644 |     // Data end calendar events.
 | 
        
           |  |  | 645 |     $event = new stdClass();
 | 
        
           |  |  | 646 |     $event->type = CALENDAR_EVENT_TYPE_ACTION;
 | 
        
           |  |  | 647 |     $event->eventtype = DATA_EVENT_TYPE_CLOSE;
 | 
        
           |  |  | 648 |     if ($event->id = $DB->get_field('event', 'id',
 | 
        
           |  |  | 649 |             array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => $event->eventtype))) {
 | 
        
           |  |  | 650 |         if ($data->timeavailableto > 0) {
 | 
        
           |  |  | 651 |             // Calendar event exists so update it.
 | 
        
           |  |  | 652 |             $event->name         = get_string('calendarend', 'data', $data->name);
 | 
        
           |  |  | 653 |             $event->description  = format_module_intro('data', $data, $data->coursemodule, false);
 | 
        
           |  |  | 654 |             $event->format       = FORMAT_HTML;
 | 
        
           |  |  | 655 |             $event->timestart    = $data->timeavailableto;
 | 
        
           |  |  | 656 |             $event->timesort     = $data->timeavailableto;
 | 
        
           |  |  | 657 |             $event->visible      = instance_is_visible('data', $data);
 | 
        
           |  |  | 658 |             $event->timeduration = 0;
 | 
        
           |  |  | 659 |             $calendarevent = calendar_event::load($event->id);
 | 
        
           |  |  | 660 |             $calendarevent->update($event, false);
 | 
        
           |  |  | 661 |         } else {
 | 
        
           |  |  | 662 |             // Calendar event is on longer needed.
 | 
        
           |  |  | 663 |             $calendarevent = calendar_event::load($event->id);
 | 
        
           |  |  | 664 |             $calendarevent->delete();
 | 
        
           |  |  | 665 |         }
 | 
        
           |  |  | 666 |     } else {
 | 
        
           |  |  | 667 |         // Event doesn't exist so create one.
 | 
        
           |  |  | 668 |         if (isset($data->timeavailableto) && $data->timeavailableto > 0) {
 | 
        
           |  |  | 669 |             $event->name         = get_string('calendarend', 'data', $data->name);
 | 
        
           |  |  | 670 |             $event->description  = format_module_intro('data', $data, $data->coursemodule, false);
 | 
        
           |  |  | 671 |             $event->format       = FORMAT_HTML;
 | 
        
           |  |  | 672 |             $event->courseid     = $data->course;
 | 
        
           |  |  | 673 |             $event->groupid      = 0;
 | 
        
           |  |  | 674 |             $event->userid       = 0;
 | 
        
           |  |  | 675 |             $event->modulename   = 'data';
 | 
        
           |  |  | 676 |             $event->instance     = $data->id;
 | 
        
           |  |  | 677 |             $event->timestart    = $data->timeavailableto;
 | 
        
           |  |  | 678 |             $event->timesort     = $data->timeavailableto;
 | 
        
           |  |  | 679 |             $event->visible      = instance_is_visible('data', $data);
 | 
        
           |  |  | 680 |             $event->timeduration = 0;
 | 
        
           |  |  | 681 |             calendar_event::create($event, false);
 | 
        
           |  |  | 682 |         }
 | 
        
           |  |  | 683 |     }
 | 
        
           |  |  | 684 | }
 | 
        
           |  |  | 685 |   | 
        
           |  |  | 686 | /**
 | 
        
           |  |  | 687 |  * Check if a database is available for the current user.
 | 
        
           |  |  | 688 |  *
 | 
        
           |  |  | 689 |  * @param  stdClass  $data            database record
 | 
        
           |  |  | 690 |  * @param  boolean $canmanageentries  optional, if the user can manage entries
 | 
        
           |  |  | 691 |  * @param  stdClass  $context         Module context, required if $canmanageentries is not set
 | 
        
           |  |  | 692 |  * @return array                      status (available or not and possible warnings)
 | 
        
           |  |  | 693 |  * @since  Moodle 3.3
 | 
        
           |  |  | 694 |  */
 | 
        
           |  |  | 695 | function data_get_time_availability_status($data, $canmanageentries = null, $context = null) {
 | 
        
           |  |  | 696 |     $open = true;
 | 
        
           |  |  | 697 |     $closed = false;
 | 
        
           |  |  | 698 |     $warnings = array();
 | 
        
           |  |  | 699 |   | 
        
           |  |  | 700 |     if ($canmanageentries === null) {
 | 
        
           |  |  | 701 |         $canmanageentries = has_capability('mod/data:manageentries', $context);
 | 
        
           |  |  | 702 |     }
 | 
        
           |  |  | 703 |   | 
        
           |  |  | 704 |     if (!$canmanageentries) {
 | 
        
           |  |  | 705 |         $timenow = time();
 | 
        
           |  |  | 706 |   | 
        
           |  |  | 707 |         if (!empty($data->timeavailablefrom) and $data->timeavailablefrom > $timenow) {
 | 
        
           |  |  | 708 |             $open = false;
 | 
        
           |  |  | 709 |         }
 | 
        
           |  |  | 710 |         if (!empty($data->timeavailableto) and $timenow > $data->timeavailableto) {
 | 
        
           |  |  | 711 |             $closed = true;
 | 
        
           |  |  | 712 |         }
 | 
        
           |  |  | 713 |   | 
        
           |  |  | 714 |         if (!$open or $closed) {
 | 
        
           |  |  | 715 |             if (!$open) {
 | 
        
           |  |  | 716 |                 $warnings['notopenyet'] = userdate($data->timeavailablefrom);
 | 
        
           |  |  | 717 |             }
 | 
        
           |  |  | 718 |             if ($closed) {
 | 
        
           |  |  | 719 |                 $warnings['expired'] = userdate($data->timeavailableto);
 | 
        
           |  |  | 720 |             }
 | 
        
           |  |  | 721 |             return array(false, $warnings);
 | 
        
           |  |  | 722 |         }
 | 
        
           |  |  | 723 |     }
 | 
        
           |  |  | 724 |   | 
        
           |  |  | 725 |     // Database is available.
 | 
        
           |  |  | 726 |     return array(true, $warnings);
 | 
        
           |  |  | 727 | }
 | 
        
           |  |  | 728 |   | 
        
           |  |  | 729 | /**
 | 
        
           |  |  | 730 |  * Requires a database to be available for the current user.
 | 
        
           |  |  | 731 |  *
 | 
        
           |  |  | 732 |  * @param  stdClass  $data            database record
 | 
        
           |  |  | 733 |  * @param  boolean $canmanageentries  optional, if the user can manage entries
 | 
        
           |  |  | 734 |  * @param  stdClass  $context          Module context, required if $canmanageentries is not set
 | 
        
           |  |  | 735 |  * @throws moodle_exception
 | 
        
           |  |  | 736 |  * @since  Moodle 3.3
 | 
        
           |  |  | 737 |  */
 | 
        
           |  |  | 738 | function data_require_time_available($data, $canmanageentries = null, $context = null) {
 | 
        
           |  |  | 739 |   | 
        
           |  |  | 740 |     list($available, $warnings) = data_get_time_availability_status($data, $canmanageentries, $context);
 | 
        
           |  |  | 741 |   | 
        
           |  |  | 742 |     if (!$available) {
 | 
        
           |  |  | 743 |         $reason = current(array_keys($warnings));
 | 
        
           |  |  | 744 |         throw new moodle_exception($reason, 'data', '', $warnings[$reason]);
 | 
        
           |  |  | 745 |     }
 | 
        
           |  |  | 746 | }
 | 
        
           |  |  | 747 |   | 
        
           |  |  | 748 | /**
 | 
        
           |  |  | 749 |  * Return the number of entries left to add to complete the activity.
 | 
        
           |  |  | 750 |  *
 | 
        
           |  |  | 751 |  * @param  stdClass $data           database object
 | 
        
           |  |  | 752 |  * @param  int $numentries          the number of entries the current user has created
 | 
        
           |  |  | 753 |  * @param  bool $canmanageentries   whether the user can manage entries (teachers, managers)
 | 
        
           |  |  | 754 |  * @return int the number of entries left, 0 if no entries left or if is not required
 | 
        
           |  |  | 755 |  * @since  Moodle 3.3
 | 
        
           |  |  | 756 |  */
 | 
        
           |  |  | 757 | function data_get_entries_left_to_add($data, $numentries, $canmanageentries) {
 | 
        
           |  |  | 758 |     if ($data->requiredentries > 0 && $numentries < $data->requiredentries && !$canmanageentries) {
 | 
        
           |  |  | 759 |         return $data->requiredentries - $numentries;
 | 
        
           |  |  | 760 |     }
 | 
        
           |  |  | 761 |     return 0;
 | 
        
           |  |  | 762 | }
 | 
        
           |  |  | 763 |   | 
        
           |  |  | 764 | /**
 | 
        
           |  |  | 765 |  * Return the number of entires left to add to view other users entries..
 | 
        
           |  |  | 766 |  *
 | 
        
           |  |  | 767 |  * @param  stdClass $data           database object
 | 
        
           |  |  | 768 |  * @param  int $numentries          the number of entries the current user has created
 | 
        
           |  |  | 769 |  * @param  bool $canmanageentries   whether the user can manage entries (teachers, managers)
 | 
        
           |  |  | 770 |  * @return int the number of entries left, 0 if no entries left or if is not required
 | 
        
           |  |  | 771 |  * @since  Moodle 3.3
 | 
        
           |  |  | 772 |  */
 | 
        
           |  |  | 773 | function data_get_entries_left_to_view($data, $numentries, $canmanageentries) {
 | 
        
           |  |  | 774 |     if ($data->requiredentriestoview > 0 && $numentries < $data->requiredentriestoview && !$canmanageentries) {
 | 
        
           |  |  | 775 |         return $data->requiredentriestoview - $numentries;
 | 
        
           |  |  | 776 |     }
 | 
        
           |  |  | 777 |     return 0;
 | 
        
           |  |  | 778 | }
 | 
        
           |  |  | 779 |   | 
        
           |  |  | 780 | /**
 | 
        
           |  |  | 781 |  * Returns data records tagged with a specified tag.
 | 
        
           |  |  | 782 |  *
 | 
        
           |  |  | 783 |  * This is a callback used by the tag area mod_data/data_records to search for data records
 | 
        
           |  |  | 784 |  * tagged with a specific tag.
 | 
        
           |  |  | 785 |  *
 | 
        
           |  |  | 786 |  * @param core_tag_tag $tag
 | 
        
           |  |  | 787 |  * @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
 | 
        
           |  |  | 788 |  *             are displayed on the page and the per-page limit may be bigger
 | 
        
           |  |  | 789 |  * @param int $fromctx context id where the link was displayed, may be used by callbacks
 | 
        
           |  |  | 790 |  *            to display items in the same context first
 | 
        
           |  |  | 791 |  * @param int $ctx context id where to search for records
 | 
        
           |  |  | 792 |  * @param bool $rec search in subcontexts as well
 | 
        
           |  |  | 793 |  * @param int $page 0-based number of page being displayed
 | 
        
           |  |  | 794 |  * @return \core_tag\output\tagindex
 | 
        
           |  |  | 795 |  */
 | 
        
           |  |  | 796 | function mod_data_get_tagged_records($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = true, $page = 0) {
 | 
        
           |  |  | 797 |     global $DB, $OUTPUT, $USER;
 | 
        
           |  |  | 798 |     $perpage = $exclusivemode ? 20 : 5;
 | 
        
           |  |  | 799 |   | 
        
           |  |  | 800 |     // Build the SQL query.
 | 
        
           |  |  | 801 |     $ctxselect = context_helper::get_preload_record_columns_sql('ctx');
 | 
        
           |  |  | 802 |     $query = "SELECT dr.id, dr.dataid, dr.approved, d.timeviewfrom, d.timeviewto, dr.groupid, d.approval, dr.userid,
 | 
        
           |  |  | 803 |                      d.requiredentriestoview, cm.id AS cmid, c.id AS courseid, c.shortname, c.fullname, $ctxselect
 | 
        
           |  |  | 804 |                 FROM {data_records} dr
 | 
        
           |  |  | 805 |                 JOIN {data} d
 | 
        
           |  |  | 806 |                   ON d.id = dr.dataid
 | 
        
           |  |  | 807 |                 JOIN {modules} m
 | 
        
           |  |  | 808 |                   ON m.name = 'data'
 | 
        
           |  |  | 809 |                 JOIN {course_modules} cm
 | 
        
           |  |  | 810 |                   ON cm.module = m.id AND cm.instance = d.id
 | 
        
           |  |  | 811 |                 JOIN {tag_instance} tt
 | 
        
           |  |  | 812 |                   ON dr.id = tt.itemid
 | 
        
           |  |  | 813 |                 JOIN {course} c
 | 
        
           |  |  | 814 |                   ON cm.course = c.id
 | 
        
           |  |  | 815 |                 JOIN {context} ctx
 | 
        
           |  |  | 816 |                   ON ctx.instanceid = cm.id AND ctx.contextlevel = :coursemodulecontextlevel
 | 
        
           |  |  | 817 |                WHERE tt.itemtype = :itemtype
 | 
        
           |  |  | 818 |                  AND tt.tagid = :tagid
 | 
        
           |  |  | 819 |                  AND tt.component = :component
 | 
        
           |  |  | 820 |                  AND cm.deletioninprogress = 0
 | 
        
           |  |  | 821 |                  AND dr.id %ITEMFILTER%
 | 
        
           |  |  | 822 |                  AND c.id %COURSEFILTER%";
 | 
        
           |  |  | 823 |   | 
        
           |  |  | 824 |     $params = array(
 | 
        
           |  |  | 825 |         'itemtype' => 'data_records',
 | 
        
           |  |  | 826 |         'tagid' => $tag->id,
 | 
        
           |  |  | 827 |         'component' => 'mod_data',
 | 
        
           |  |  | 828 |         'coursemodulecontextlevel' => CONTEXT_MODULE
 | 
        
           |  |  | 829 |     );
 | 
        
           |  |  | 830 |   | 
        
           |  |  | 831 |     if ($ctx) {
 | 
        
           |  |  | 832 |         $context = $ctx ? context::instance_by_id($ctx) : context_system::instance();
 | 
        
           |  |  | 833 |         $query .= $rec ? ' AND (ctx.id = :contextid OR ctx.path LIKE :path)' : ' AND ctx.id = :contextid';
 | 
        
           |  |  | 834 |         $params['contextid'] = $context->id;
 | 
        
           |  |  | 835 |         $params['path'] = $context->path . '/%';
 | 
        
           |  |  | 836 |     }
 | 
        
           |  |  | 837 |   | 
        
           |  |  | 838 |     $query .= " ORDER BY ";
 | 
        
           |  |  | 839 |     if ($fromctx) {
 | 
        
           |  |  | 840 |         // In order-clause specify that modules from inside "fromctx" context should be returned first.
 | 
        
           |  |  | 841 |         $fromcontext = context::instance_by_id($fromctx);
 | 
        
           |  |  | 842 |         $query .= ' (CASE WHEN ctx.id = :fromcontextid OR ctx.path LIKE :frompath THEN 0 ELSE 1 END),';
 | 
        
           |  |  | 843 |         $params['fromcontextid'] = $fromcontext->id;
 | 
        
           |  |  | 844 |         $params['frompath'] = $fromcontext->path . '/%';
 | 
        
           |  |  | 845 |     }
 | 
        
           |  |  | 846 |     $query .= ' c.sortorder, cm.id, dr.id';
 | 
        
           |  |  | 847 |   | 
        
           |  |  | 848 |     $totalpages = $page + 1;
 | 
        
           |  |  | 849 |   | 
        
           |  |  | 850 |     // Use core_tag_index_builder to build and filter the list of items.
 | 
        
           |  |  | 851 |     $builder = new core_tag_index_builder('mod_data', 'data_records', $query, $params, $page * $perpage, $perpage + 1);
 | 
        
           |  |  | 852 |     $now = time();
 | 
        
           |  |  | 853 |     $entrycount = [];
 | 
        
           |  |  | 854 |     $activitygroupmode = [];
 | 
        
           |  |  | 855 |     $usergroups = [];
 | 
        
           |  |  | 856 |     $titlefields = [];
 | 
        
           |  |  | 857 |     while ($item = $builder->has_item_that_needs_access_check()) {
 | 
        
           |  |  | 858 |         context_helper::preload_from_record($item);
 | 
        
           |  |  | 859 |         $modinfo = get_fast_modinfo($item->courseid);
 | 
        
           |  |  | 860 |         $cm = $modinfo->get_cm($item->cmid);
 | 
        
           |  |  | 861 |         $context = \context_module::instance($cm->id);
 | 
        
           |  |  | 862 |         $courseid = $item->courseid;
 | 
        
           |  |  | 863 |   | 
        
           |  |  | 864 |         if (!$builder->can_access_course($courseid)) {
 | 
        
           |  |  | 865 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 866 |             continue;
 | 
        
           |  |  | 867 |         }
 | 
        
           |  |  | 868 |   | 
        
           |  |  | 869 |         if (!$cm->uservisible) {
 | 
        
           |  |  | 870 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 871 |             continue;
 | 
        
           |  |  | 872 |         }
 | 
        
           |  |  | 873 |   | 
        
           |  |  | 874 |         if (!has_capability('mod/data:viewentry', $context)) {
 | 
        
           |  |  | 875 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 876 |             continue;
 | 
        
           |  |  | 877 |         }
 | 
        
           |  |  | 878 |   | 
        
           |  |  | 879 |         if ($USER->id != $item->userid && (($item->timeviewfrom && $now < $item->timeviewfrom)
 | 
        
           |  |  | 880 |                 || ($item->timeviewto && $now > $item->timeviewto))) {
 | 
        
           |  |  | 881 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 882 |             continue;
 | 
        
           |  |  | 883 |         }
 | 
        
           |  |  | 884 |   | 
        
           |  |  | 885 |         if ($USER->id != $item->userid && $item->approval && !$item->approved) {
 | 
        
           |  |  | 886 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 887 |             continue;
 | 
        
           |  |  | 888 |         }
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |         if ($item->requiredentriestoview) {
 | 
        
           |  |  | 891 |             if (!isset($entrycount[$item->dataid])) {
 | 
        
           |  |  | 892 |                 $entrycount[$item->dataid] = $DB->count_records('data_records', array('dataid' => $item->dataid));
 | 
        
           |  |  | 893 |             }
 | 
        
           |  |  | 894 |             $sufficiententries = $item->requiredentriestoview > $entrycount[$item->dataid];
 | 
        
           |  |  | 895 |             $builder->set_accessible($item, $sufficiententries);
 | 
        
           |  |  | 896 |         }
 | 
        
           |  |  | 897 |   | 
        
           |  |  | 898 |         if (!isset($activitygroupmode[$cm->id])) {
 | 
        
           |  |  | 899 |             $activitygroupmode[$cm->id] = groups_get_activity_groupmode($cm);
 | 
        
           |  |  | 900 |         }
 | 
        
           |  |  | 901 |   | 
        
           |  |  | 902 |         if (!isset($usergroups[$item->groupid])) {
 | 
        
           |  |  | 903 |             $usergroups[$item->groupid] = groups_is_member($item->groupid, $USER->id);
 | 
        
           |  |  | 904 |         }
 | 
        
           |  |  | 905 |   | 
        
           |  |  | 906 |         if ($activitygroupmode[$cm->id] == SEPARATEGROUPS && !$usergroups[$item->groupid]) {
 | 
        
           |  |  | 907 |             $builder->set_accessible($item, false);
 | 
        
           |  |  | 908 |             continue;
 | 
        
           |  |  | 909 |         }
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 |         $builder->set_accessible($item, true);
 | 
        
           |  |  | 912 |     }
 | 
        
           |  |  | 913 |   | 
        
           |  |  | 914 |     $items = $builder->get_items();
 | 
        
           |  |  | 915 |     if (count($items) > $perpage) {
 | 
        
           |  |  | 916 |         $totalpages = $page + 2; // We don't need exact page count, just indicate that the next page exists.
 | 
        
           |  |  | 917 |         array_pop($items);
 | 
        
           |  |  | 918 |     }
 | 
        
           |  |  | 919 |   | 
        
           |  |  | 920 |     // Build the display contents.
 | 
        
           |  |  | 921 |     if ($items) {
 | 
        
           |  |  | 922 |         $tagfeed = new core_tag\output\tagfeed();
 | 
        
           |  |  | 923 |         foreach ($items as $item) {
 | 
        
           |  |  | 924 |             context_helper::preload_from_record($item);
 | 
        
           |  |  | 925 |             $modinfo = get_fast_modinfo($item->courseid);
 | 
        
           |  |  | 926 |             $cm = $modinfo->get_cm($item->cmid);
 | 
        
           |  |  | 927 |             $pageurl = new moodle_url('/mod/data/view.php', array(
 | 
        
           |  |  | 928 |                     'rid' => $item->id,
 | 
        
           |  |  | 929 |                     'd' => $item->dataid
 | 
        
           |  |  | 930 |             ));
 | 
        
           |  |  | 931 |   | 
        
           |  |  | 932 |             if (!isset($titlefields[$item->dataid])) {
 | 
        
           |  |  | 933 |                 $titlefields[$item->dataid] = data_get_tag_title_field($item->dataid);
 | 
        
           |  |  | 934 |             }
 | 
        
           |  |  | 935 |   | 
        
           |  |  | 936 |             $pagename = data_get_tag_title_for_entry($titlefields[$item->dataid], $item);
 | 
        
           |  |  | 937 |             $pagename = html_writer::link($pageurl, $pagename);
 | 
        
           |  |  | 938 |             $courseurl = course_get_url($item->courseid, $cm->sectionnum);
 | 
        
           |  |  | 939 |             $cmname = html_writer::link($cm->url, $cm->get_formatted_name());
 | 
        
           |  |  | 940 |             $coursename = format_string($item->fullname, true, array('context' => context_course::instance($item->courseid)));
 | 
        
           |  |  | 941 |             $coursename = html_writer::link($courseurl, $coursename);
 | 
        
           |  |  | 942 |             $icon = html_writer::link($pageurl, html_writer::empty_tag('img', array('src' => $cm->get_icon_url())));
 | 
        
           |  |  | 943 |             $tagfeed->add($icon, $pagename, $cmname . '<br>' . $coursename);
 | 
        
           |  |  | 944 |         }
 | 
        
           |  |  | 945 |         $content = $OUTPUT->render_from_template('core_tag/tagfeed', $tagfeed->export_for_template($OUTPUT));
 | 
        
           |  |  | 946 |   | 
        
           |  |  | 947 |         return new core_tag\output\tagindex($tag, 'mod_data', 'data_records', $content, $exclusivemode,
 | 
        
           |  |  | 948 |             $fromctx, $ctx, $rec, $page, $totalpages);
 | 
        
           |  |  | 949 |     }
 | 
        
           |  |  | 950 | }
 | 
        
           |  |  | 951 |   | 
        
           |  |  | 952 | /**
 | 
        
           |  |  | 953 |  * Get the title of a field to show when displaying tag results.
 | 
        
           |  |  | 954 |  *
 | 
        
           |  |  | 955 |  * @param int $dataid The id of the data field
 | 
        
           |  |  | 956 |  * @return stdClass The field data from the 'data_fields' table as well as it's priority
 | 
        
           |  |  | 957 |  */
 | 
        
           |  |  | 958 | function data_get_tag_title_field($dataid) {
 | 
        
           |  |  | 959 |     global $DB, $CFG;
 | 
        
           |  |  | 960 |   | 
        
           |  |  | 961 |     $validfieldtypes = array('text', 'textarea', 'menu', 'radiobutton', 'checkbox', 'multimenu', 'url');
 | 
        
           |  |  | 962 |     $fields = $DB->get_records('data_fields', ['dataid' => $dataid]);
 | 
        
           |  |  | 963 |     $template = $DB->get_field('data', 'addtemplate', ['id' => $dataid]);
 | 
        
           |  |  | 964 |     if (empty($template)) {
 | 
        
           |  |  | 965 |         $data = $DB->get_record('data', ['id' => $dataid]);
 | 
        
           |  |  | 966 |         $template = data_generate_default_template($data, 'addtemplate', 0, false, false);
 | 
        
           |  |  | 967 |     }
 | 
        
           |  |  | 968 |   | 
        
           |  |  | 969 |     $filteredfields = [];
 | 
        
           |  |  | 970 |   | 
        
           |  |  | 971 |     foreach ($fields as $field) {
 | 
        
           |  |  | 972 |         if (!in_array($field->type, $validfieldtypes)) {
 | 
        
           |  |  | 973 |             continue;
 | 
        
           |  |  | 974 |         }
 | 
        
           |  |  | 975 |         $field->addtemplateposition = strpos($template, '[['.$field->name.']]');
 | 
        
           |  |  | 976 |         if ($field->addtemplateposition === false) {
 | 
        
           |  |  | 977 |             continue;
 | 
        
           |  |  | 978 |         }
 | 
        
           |  |  | 979 |         $field->type = clean_param($field->type, PARAM_ALPHA);
 | 
        
           |  |  | 980 |         $filepath = $CFG->dirroot . '/mod/data/field/' . $field->type . '/field.class.php';
 | 
        
           |  |  | 981 |         if (!file_exists($filepath)) {
 | 
        
           |  |  | 982 |             continue;
 | 
        
           |  |  | 983 |         }
 | 
        
           |  |  | 984 |         require_once($filepath);
 | 
        
           |  |  | 985 |         $classname = 'data_field_' . $field->type;
 | 
        
           |  |  | 986 |         $field->priority = $classname::get_priority();
 | 
        
           |  |  | 987 |         $filteredfields[] = $field;
 | 
        
           |  |  | 988 |     }
 | 
        
           |  |  | 989 |   | 
        
           |  |  | 990 |     $sort = function($record1, $record2) {
 | 
        
           |  |  | 991 |         // If a content's fieldtype is compulsory in the database than it would have priority than any other non-compulsory content.
 | 
        
           |  |  | 992 |         if (($record1->required && $record2->required) || (!$record1->required && !$record2->required)) {
 | 
        
           |  |  | 993 |             if ($record1->priority === $record2->priority) {
 | 
        
           |  |  | 994 |                 return $record1->id < $record2->id ? 1 : -1;
 | 
        
           |  |  | 995 |             }
 | 
        
           |  |  | 996 |   | 
        
           |  |  | 997 |             return $record1->priority < $record2->priority ? -1 : 1;
 | 
        
           |  |  | 998 |         } else if ($record1->required && !$record2->required) {
 | 
        
           |  |  | 999 |             return 1;
 | 
        
           |  |  | 1000 |         } else {
 | 
        
           |  |  | 1001 |             return -1;
 | 
        
           |  |  | 1002 |         }
 | 
        
           |  |  | 1003 |     };
 | 
        
           |  |  | 1004 |   | 
        
           |  |  | 1005 |     usort($filteredfields, $sort);
 | 
        
           |  |  | 1006 |   | 
        
           |  |  | 1007 |     return array_shift($filteredfields);
 | 
        
           |  |  | 1008 | }
 | 
        
           |  |  | 1009 |   | 
        
           |  |  | 1010 | /**
 | 
        
           |  |  | 1011 |  * Get the title of an entry to show when displaying tag results.
 | 
        
           |  |  | 1012 |  *
 | 
        
           |  |  | 1013 |  * @param stdClass $field The field from the 'data_fields' table
 | 
        
           |  |  | 1014 |  * @param stdClass $entry The entry from the 'data_records' table
 | 
        
           |  |  | 1015 |  * @return string|null It will return the title of the entry or null if the field type is not available.
 | 
        
           |  |  | 1016 |  */
 | 
        
           |  |  | 1017 | function data_get_tag_title_for_entry($field, $entry) {
 | 
        
           |  |  | 1018 |     global $CFG, $DB;
 | 
        
           |  |  | 1019 |   | 
        
           |  |  | 1020 |     if (!isset($field->type)) {
 | 
        
           |  |  | 1021 |         return null;
 | 
        
           |  |  | 1022 |     }
 | 
        
           |  |  | 1023 |     $field->type = clean_param($field->type, PARAM_ALPHA);
 | 
        
           |  |  | 1024 |     $filepath = $CFG->dirroot . '/mod/data/field/' . $field->type . '/field.class.php';
 | 
        
           |  |  | 1025 |     if (!file_exists($filepath)) {
 | 
        
           |  |  | 1026 |         return null;
 | 
        
           |  |  | 1027 |     }
 | 
        
           |  |  | 1028 |     require_once($filepath);
 | 
        
           |  |  | 1029 |   | 
        
           |  |  | 1030 |     $classname = 'data_field_' . $field->type;
 | 
        
           |  |  | 1031 |     $sql = "SELECT dc.*
 | 
        
           |  |  | 1032 |               FROM {data_content} dc
 | 
        
           |  |  | 1033 |         INNER JOIN {data_fields} df
 | 
        
           |  |  | 1034 |                 ON dc.fieldid = df.id
 | 
        
           |  |  | 1035 |              WHERE df.id = :fieldid
 | 
        
           |  |  | 1036 |                AND dc.recordid = :recordid";
 | 
        
           |  |  | 1037 |     $fieldcontents = $DB->get_record_sql($sql, array('recordid' => $entry->id, 'fieldid' => $field->id));
 | 
        
           |  |  | 1038 |   | 
        
           |  |  | 1039 |     return $classname::get_content_value($fieldcontents);
 | 
        
           |  |  | 1040 | }
 | 
        
           |  |  | 1041 |   | 
        
           |  |  | 1042 | /**
 | 
        
           |  |  | 1043 |  * Search entries in a database.
 | 
        
           |  |  | 1044 |  *
 | 
        
           |  |  | 1045 |  * @param  stdClass  $data         database object
 | 
        
           |  |  | 1046 |  * @param  stdClass  $cm           course module object
 | 
        
           |  |  | 1047 |  * @param  stdClass  $context      context object
 | 
        
           |  |  | 1048 |  * @param  stdClass  $mode         in which mode we are viewing the database (list, single)
 | 
        
           |  |  | 1049 |  * @param  int  $currentgroup      the current group being used
 | 
        
           |  |  | 1050 |  * @param  str  $search            search for this text in the entry data
 | 
        
           |  |  | 1051 |  * @param  str  $sort              the field to sort by
 | 
        
           |  |  | 1052 |  * @param  str  $order             the order to use when sorting
 | 
        
           |  |  | 1053 |  * @param  int $page               for pagination, the current page
 | 
        
           |  |  | 1054 |  * @param  int $perpage            entries per page
 | 
        
           |  |  | 1055 |  * @param  bool  $advanced         whether we are using or not advanced search
 | 
        
           |  |  | 1056 |  * @param  array  $searcharray     when using advanced search, the advanced data to use
 | 
        
           |  |  | 1057 |  * @param  stdClass  $record       if we jsut want this record after doing all the access checks
 | 
        
           |  |  | 1058 |  * @return array the entries found among other data related to the search
 | 
        
           |  |  | 1059 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1060 |  */
 | 
        
           |  |  | 1061 | function data_search_entries($data, $cm, $context, $mode, $currentgroup, $search = '', $sort = null, $order = null, $page = 0,
 | 
        
           |  |  | 1062 |         $perpage = 0, $advanced = null, $searcharray = null, $record = null) {
 | 
        
           |  |  | 1063 |     global $DB, $USER;
 | 
        
           |  |  | 1064 |   | 
        
           |  |  | 1065 |     if ($sort === null) {
 | 
        
           |  |  | 1066 |         $sort = $data->defaultsort;
 | 
        
           |  |  | 1067 |     }
 | 
        
           |  |  | 1068 |     if ($order === null) {
 | 
        
           |  |  | 1069 |         $order = ($data->defaultsortdir == 0) ? 'ASC' : 'DESC';
 | 
        
           |  |  | 1070 |     }
 | 
        
           |  |  | 1071 |     if ($searcharray === null) {
 | 
        
           |  |  | 1072 |         $searcharray = array();
 | 
        
           |  |  | 1073 |     }
 | 
        
           |  |  | 1074 |   | 
        
           |  |  | 1075 |     if (core_text::strlen($search) < 2) {
 | 
        
           |  |  | 1076 |         $search = '';
 | 
        
           |  |  | 1077 |     }
 | 
        
           |  |  | 1078 |   | 
        
           |  |  | 1079 |     $approvecap = has_capability('mod/data:approve', $context);
 | 
        
           |  |  | 1080 |     $canmanageentries = has_capability('mod/data:manageentries', $context);
 | 
        
           |  |  | 1081 |   | 
        
           |  |  | 1082 |     // If a student is not part of a group and seperate groups is enabled, we don't
 | 
        
           |  |  | 1083 |     // want them seeing all records.
 | 
        
           |  |  | 1084 |     $groupmode = groups_get_activity_groupmode($cm);
 | 
        
           | 1441 | ariadna | 1085 |     $canviewallrecords = $groupmode != SEPARATEGROUPS || has_capability('moodle/site:accessallgroups', $context);
 | 
        
           | 1 | efrain | 1086 |   | 
        
           |  |  | 1087 |     $numentries = data_numentries($data);
 | 
        
           |  |  | 1088 |     $requiredentriesallowed = true;
 | 
        
           |  |  | 1089 |     if (data_get_entries_left_to_view($data, $numentries, $canmanageentries)) {
 | 
        
           |  |  | 1090 |         $requiredentriesallowed = false;
 | 
        
           |  |  | 1091 |     }
 | 
        
           |  |  | 1092 |   | 
        
           |  |  | 1093 |     // Initialise the first group of params for advanced searches.
 | 
        
           |  |  | 1094 |     $initialparams   = array();
 | 
        
           |  |  | 1095 |     $params = array(); // Named params array.
 | 
        
           |  |  | 1096 |   | 
        
           |  |  | 1097 |     // Setup group and approve restrictions.
 | 
        
           |  |  | 1098 |     if (!$approvecap && $data->approval) {
 | 
        
           |  |  | 1099 |         if (isloggedin()) {
 | 
        
           |  |  | 1100 |             $approveselect = ' AND (r.approved=1 OR r.userid=:myid1) ';
 | 
        
           |  |  | 1101 |             $params['myid1'] = $USER->id;
 | 
        
           |  |  | 1102 |             $initialparams['myid1'] = $params['myid1'];
 | 
        
           |  |  | 1103 |         } else {
 | 
        
           |  |  | 1104 |             $approveselect = ' AND r.approved=1 ';
 | 
        
           |  |  | 1105 |         }
 | 
        
           |  |  | 1106 |     } else {
 | 
        
           |  |  | 1107 |         $approveselect = ' ';
 | 
        
           |  |  | 1108 |     }
 | 
        
           |  |  | 1109 |   | 
        
           |  |  | 1110 |     if ($currentgroup) {
 | 
        
           |  |  | 1111 |         $groupselect = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
 | 
        
           |  |  | 1112 |         $params['currentgroup'] = $currentgroup;
 | 
        
           |  |  | 1113 |         $initialparams['currentgroup'] = $params['currentgroup'];
 | 
        
           |  |  | 1114 |     } else {
 | 
        
           |  |  | 1115 |         if ($canviewallrecords) {
 | 
        
           |  |  | 1116 |             $groupselect = ' ';
 | 
        
           |  |  | 1117 |         } else {
 | 
        
           |  |  | 1118 |             // If separate groups are enabled and the user isn't in a group or
 | 
        
           |  |  | 1119 |             // a teacher, manager, admin etc, then just show them entries for 'All participants'.
 | 
        
           |  |  | 1120 |             $groupselect = " AND r.groupid = 0";
 | 
        
           |  |  | 1121 |         }
 | 
        
           |  |  | 1122 |     }
 | 
        
           |  |  | 1123 |   | 
        
           |  |  | 1124 |     // Init some variables to be used by advanced search.
 | 
        
           |  |  | 1125 |     $advsearchselect = '';
 | 
        
           |  |  | 1126 |     $advwhere        = '';
 | 
        
           |  |  | 1127 |     $advtables       = '';
 | 
        
           |  |  | 1128 |     $advparams       = array();
 | 
        
           |  |  | 1129 |     // This is used for the initial reduction of advanced search results with required entries.
 | 
        
           |  |  | 1130 |     $entrysql        = '';
 | 
        
           |  |  | 1131 |     $userfieldsapi = \core_user\fields::for_userpic()->excluding('id');
 | 
        
           |  |  | 1132 |     $namefields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
 | 
        
           |  |  | 1133 |   | 
        
           |  |  | 1134 |     // Find the field we are sorting on.
 | 
        
           |  |  | 1135 |     if ($sort <= 0 || !($sortfield = data_get_field_from_id($sort, $data))) {
 | 
        
           |  |  | 1136 |   | 
        
           |  |  | 1137 |         switch ($sort) {
 | 
        
           |  |  | 1138 |             case DATA_LASTNAME:
 | 
        
           |  |  | 1139 |                 $ordering = "u.lastname $order, u.firstname $order";
 | 
        
           |  |  | 1140 |                 break;
 | 
        
           |  |  | 1141 |             case DATA_FIRSTNAME:
 | 
        
           |  |  | 1142 |                 $ordering = "u.firstname $order, u.lastname $order";
 | 
        
           |  |  | 1143 |                 break;
 | 
        
           |  |  | 1144 |             case DATA_APPROVED:
 | 
        
           |  |  | 1145 |                 $ordering = "r.approved $order, r.timecreated $order";
 | 
        
           |  |  | 1146 |                 break;
 | 
        
           |  |  | 1147 |             case DATA_TIMEMODIFIED:
 | 
        
           |  |  | 1148 |                 $ordering = "r.timemodified $order";
 | 
        
           |  |  | 1149 |                 break;
 | 
        
           |  |  | 1150 |             case DATA_TIMEADDED:
 | 
        
           |  |  | 1151 |             default:
 | 
        
           |  |  | 1152 |                 $sort     = 0;
 | 
        
           |  |  | 1153 |                 $ordering = "r.timecreated $order";
 | 
        
           |  |  | 1154 |         }
 | 
        
           |  |  | 1155 |   | 
        
           |  |  | 1156 |         $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, r.groupid, r.dataid, ' . $namefields;
 | 
        
           |  |  | 1157 |         $count = ' COUNT(DISTINCT c.recordid) ';
 | 
        
           |  |  | 1158 |         $tables = '{data_content} c,{data_records} r, {user} u ';
 | 
        
           |  |  | 1159 |         $where = 'WHERE c.recordid = r.id
 | 
        
           |  |  | 1160 |                      AND r.dataid = :dataid
 | 
        
           |  |  | 1161 |                      AND r.userid = u.id ';
 | 
        
           |  |  | 1162 |         $params['dataid'] = $data->id;
 | 
        
           |  |  | 1163 |         $sortorder = " ORDER BY $ordering, r.id $order";
 | 
        
           |  |  | 1164 |         $searchselect = '';
 | 
        
           |  |  | 1165 |   | 
        
           |  |  | 1166 |         // If requiredentries is not reached, only show current user's entries.
 | 
        
           |  |  | 1167 |         if (!$requiredentriesallowed) {
 | 
        
           |  |  | 1168 |             $where .= ' AND u.id = :myid2 ';
 | 
        
           |  |  | 1169 |             $entrysql = ' AND r.userid = :myid3 ';
 | 
        
           |  |  | 1170 |             $params['myid2'] = $USER->id;
 | 
        
           |  |  | 1171 |             $initialparams['myid3'] = $params['myid2'];
 | 
        
           |  |  | 1172 |         }
 | 
        
           |  |  | 1173 |   | 
        
           |  |  | 1174 |         if ($search) {
 | 
        
           |  |  | 1175 |             $searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)."
 | 
        
           |  |  | 1176 |                               OR ".$DB->sql_like('u.firstname', ':search2', false)."
 | 
        
           |  |  | 1177 |                               OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
 | 
        
           |  |  | 1178 |             $params['search1'] = "%$search%";
 | 
        
           |  |  | 1179 |             $params['search2'] = "%$search%";
 | 
        
           |  |  | 1180 |             $params['search3'] = "%$search%";
 | 
        
           |  |  | 1181 |         } else {
 | 
        
           |  |  | 1182 |             $searchselect = ' ';
 | 
        
           |  |  | 1183 |         }
 | 
        
           |  |  | 1184 |   | 
        
           |  |  | 1185 |     } else {
 | 
        
           |  |  | 1186 |   | 
        
           |  |  | 1187 |         $sortcontent = $DB->sql_compare_text('s.' . $sortfield->get_sort_field());
 | 
        
           |  |  | 1188 |         $sortcontentfull = $sortfield->get_sort_sql($sortcontent);
 | 
        
           |  |  | 1189 |   | 
        
           |  |  | 1190 |         $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, r.groupid, r.dataid, ' . $namefields . ',
 | 
        
           |  |  | 1191 |                 ' . $sortcontentfull . ' AS sortorder ';
 | 
        
           |  |  | 1192 |         $count = ' COUNT(DISTINCT c.recordid) ';
 | 
        
           |  |  | 1193 |         $tables = '{data_content} c, {data_records} r, {user} u ';
 | 
        
           |  |  | 1194 |         $where = 'WHERE c.recordid = r.id
 | 
        
           |  |  | 1195 |                      AND r.dataid = :dataid
 | 
        
           |  |  | 1196 |                      AND r.userid = u.id ';
 | 
        
           |  |  | 1197 |         if (!$advanced) {
 | 
        
           |  |  | 1198 |             $where .= 'AND s.fieldid = :sort AND s.recordid = r.id';
 | 
        
           |  |  | 1199 |             $tables .= ',{data_content} s ';
 | 
        
           |  |  | 1200 |         }
 | 
        
           |  |  | 1201 |         $params['dataid'] = $data->id;
 | 
        
           |  |  | 1202 |         $params['sort'] = $sort;
 | 
        
           |  |  | 1203 |         $sortorder = ' ORDER BY sortorder '.$order.' , r.id ASC ';
 | 
        
           |  |  | 1204 |         $searchselect = '';
 | 
        
           |  |  | 1205 |   | 
        
           |  |  | 1206 |         // If requiredentries is not reached, only show current user's entries.
 | 
        
           |  |  | 1207 |         if (!$requiredentriesallowed) {
 | 
        
           |  |  | 1208 |             $where .= ' AND u.id = :myid2';
 | 
        
           |  |  | 1209 |             $entrysql = ' AND r.userid = :myid3';
 | 
        
           |  |  | 1210 |             $params['myid2'] = $USER->id;
 | 
        
           |  |  | 1211 |             $initialparams['myid3'] = $params['myid2'];
 | 
        
           |  |  | 1212 |         }
 | 
        
           |  |  | 1213 |   | 
        
           |  |  | 1214 |         if ($search) {
 | 
        
           |  |  | 1215 |             $searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)." OR
 | 
        
           |  |  | 1216 |                 ".$DB->sql_like('u.firstname', ':search2', false)." OR
 | 
        
           |  |  | 1217 |                 ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
 | 
        
           |  |  | 1218 |             $params['search1'] = "%$search%";
 | 
        
           |  |  | 1219 |             $params['search2'] = "%$search%";
 | 
        
           |  |  | 1220 |             $params['search3'] = "%$search%";
 | 
        
           |  |  | 1221 |         } else {
 | 
        
           |  |  | 1222 |             $searchselect = ' ';
 | 
        
           |  |  | 1223 |         }
 | 
        
           |  |  | 1224 |     }
 | 
        
           |  |  | 1225 |   | 
        
           |  |  | 1226 |     // To actually fetch the records.
 | 
        
           |  |  | 1227 |   | 
        
           |  |  | 1228 |     $fromsql    = "FROM $tables $advtables $where $advwhere $groupselect $approveselect $searchselect $advsearchselect";
 | 
        
           |  |  | 1229 |     $allparams  = array_merge($params, $advparams);
 | 
        
           |  |  | 1230 |   | 
        
           |  |  | 1231 |     // Provide initial sql statements and parameters to reduce the number of total records.
 | 
        
           |  |  | 1232 |     $initialselect = $groupselect . $approveselect . $entrysql;
 | 
        
           |  |  | 1233 |   | 
        
           |  |  | 1234 |     $recordids = data_get_all_recordids($data->id, $initialselect, $initialparams);
 | 
        
           |  |  | 1235 |     $newrecordids = data_get_advance_search_ids($recordids, $searcharray, $data->id);
 | 
        
           |  |  | 1236 |     $selectdata = $where . $groupselect . $approveselect;
 | 
        
           |  |  | 1237 |   | 
        
           |  |  | 1238 |     if (!empty($advanced)) {
 | 
        
           |  |  | 1239 |         $advancedsearchsql = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
 | 
        
           |  |  | 1240 |         $sqlselect = $advancedsearchsql['sql'];
 | 
        
           |  |  | 1241 |         $allparams = array_merge($allparams, $advancedsearchsql['params']);
 | 
        
           |  |  | 1242 |         $totalcount = count($newrecordids);
 | 
        
           |  |  | 1243 |     } else {
 | 
        
           |  |  | 1244 |         $sqlselect  = "SELECT $what $fromsql $sortorder";
 | 
        
           |  |  | 1245 |         $sqlcountselect  = "SELECT $count $fromsql";
 | 
        
           |  |  | 1246 |         $totalcount = $DB->count_records_sql($sqlcountselect, $allparams);
 | 
        
           |  |  | 1247 |     }
 | 
        
           |  |  | 1248 |   | 
        
           |  |  | 1249 |     // Work out the paging numbers and counts.
 | 
        
           |  |  | 1250 |     if (empty($searchselect) && empty($advsearchselect)) {
 | 
        
           |  |  | 1251 |         $maxcount = $totalcount;
 | 
        
           |  |  | 1252 |     } else {
 | 
        
           |  |  | 1253 |         $maxcount = count($recordids);
 | 
        
           |  |  | 1254 |     }
 | 
        
           |  |  | 1255 |   | 
        
           |  |  | 1256 |     if ($record) {     // We need to just show one, so where is it in context?
 | 
        
           |  |  | 1257 |         $nowperpage = 1;
 | 
        
           |  |  | 1258 |         $mode = 'single';
 | 
        
           |  |  | 1259 |         $page = 0;
 | 
        
           |  |  | 1260 |         // TODO MDL-33797 - Reduce this or consider redesigning the paging system.
 | 
        
           |  |  | 1261 |         if ($allrecordids = $DB->get_fieldset_sql($sqlselect, $allparams)) {
 | 
        
           |  |  | 1262 |             $page = (int)array_search($record->id, $allrecordids);
 | 
        
           |  |  | 1263 |             unset($allrecordids);
 | 
        
           |  |  | 1264 |         }
 | 
        
           |  |  | 1265 |     } else if ($mode == 'single') {  // We rely on ambient $page settings
 | 
        
           |  |  | 1266 |         $nowperpage = 1;
 | 
        
           |  |  | 1267 |   | 
        
           |  |  | 1268 |     } else {
 | 
        
           |  |  | 1269 |         $nowperpage = $perpage;
 | 
        
           |  |  | 1270 |     }
 | 
        
           |  |  | 1271 |   | 
        
           |  |  | 1272 |     // Get the actual records.
 | 
        
           |  |  | 1273 |     if (!$records = $DB->get_records_sql($sqlselect, $allparams, $page * $nowperpage, $nowperpage)) {
 | 
        
           |  |  | 1274 |         // Nothing to show!
 | 
        
           |  |  | 1275 |         if ($record) {         // Something was requested so try to show that at least (bug 5132)
 | 
        
           |  |  | 1276 |             if (data_can_view_record($data, $record, $currentgroup, $canmanageentries)) {
 | 
        
           |  |  | 1277 |                 // OK, we can show this one
 | 
        
           |  |  | 1278 |                 $records = array($record->id => $record);
 | 
        
           |  |  | 1279 |                 $totalcount = 1;
 | 
        
           |  |  | 1280 |             }
 | 
        
           |  |  | 1281 |         }
 | 
        
           |  |  | 1282 |   | 
        
           |  |  | 1283 |     }
 | 
        
           |  |  | 1284 |   | 
        
           |  |  | 1285 |     return [$records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode];
 | 
        
           |  |  | 1286 | }
 | 
        
           |  |  | 1287 |   | 
        
           |  |  | 1288 | /**
 | 
        
           |  |  | 1289 |  * Check if the current user can view the given record.
 | 
        
           |  |  | 1290 |  *
 | 
        
           |  |  | 1291 |  * @param  stdClass $data           database record
 | 
        
           |  |  | 1292 |  * @param  stdClass $record         the record (entry) to check
 | 
        
           |  |  | 1293 |  * @param  int $currentgroup        current group
 | 
        
           |  |  | 1294 |  * @param  bool $canmanageentries   if the user can manage entries
 | 
        
           |  |  | 1295 |  * @return bool true if the user can view the entry
 | 
        
           |  |  | 1296 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1297 |  */
 | 
        
           |  |  | 1298 | function data_can_view_record($data, $record, $currentgroup, $canmanageentries) {
 | 
        
           |  |  | 1299 |     global $USER;
 | 
        
           |  |  | 1300 |   | 
        
           |  |  | 1301 |     if ($canmanageentries || empty($data->approval) ||
 | 
        
           |  |  | 1302 |              $record->approved || (isloggedin() && $record->userid == $USER->id)) {
 | 
        
           |  |  | 1303 |   | 
        
           |  |  | 1304 |         if (!$currentgroup || $record->groupid == $currentgroup || $record->groupid == 0) {
 | 
        
           |  |  | 1305 |             return true;
 | 
        
           |  |  | 1306 |         }
 | 
        
           |  |  | 1307 |     }
 | 
        
           |  |  | 1308 |     return false;
 | 
        
           |  |  | 1309 | }
 | 
        
           |  |  | 1310 |   | 
        
           |  |  | 1311 | /**
 | 
        
           |  |  | 1312 |  * Return all the field instances for a given database.
 | 
        
           |  |  | 1313 |  *
 | 
        
           |  |  | 1314 |  * @param  stdClass $data database object
 | 
        
           |  |  | 1315 |  * @return array field instances
 | 
        
           |  |  | 1316 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1317 |  */
 | 
        
           |  |  | 1318 | function data_get_field_instances($data) {
 | 
        
           |  |  | 1319 |     global $DB;
 | 
        
           |  |  | 1320 |   | 
        
           |  |  | 1321 |     $instances = [];
 | 
        
           |  |  | 1322 |     if ($fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id')) {
 | 
        
           |  |  | 1323 |         foreach ($fields as $field) {
 | 
        
           |  |  | 1324 |             $instances[] = data_get_field($field, $data);
 | 
        
           |  |  | 1325 |         }
 | 
        
           |  |  | 1326 |     }
 | 
        
           |  |  | 1327 |     return $instances;
 | 
        
           |  |  | 1328 | }
 | 
        
           |  |  | 1329 |   | 
        
           |  |  | 1330 | /**
 | 
        
           |  |  | 1331 |  * Build the search array.
 | 
        
           |  |  | 1332 |  *
 | 
        
           |  |  | 1333 |  * @param  stdClass $data      the database object
 | 
        
           |  |  | 1334 |  * @param  bool $paging        if paging is being used
 | 
        
           |  |  | 1335 |  * @param  array $searcharray  the current search array (saved by session)
 | 
        
           |  |  | 1336 |  * @param  array $defaults     default values for the searchable fields
 | 
        
           |  |  | 1337 |  * @param  str $fn             the first name to search (optional)
 | 
        
           |  |  | 1338 |  * @param  str $ln             the last name to search (optional)
 | 
        
           |  |  | 1339 |  * @return array               the search array and plain search build based on the different elements
 | 
        
           |  |  | 1340 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1341 |  */
 | 
        
           |  |  | 1342 | function data_build_search_array($data, $paging, $searcharray, $defaults = null, $fn = '', $ln = '') {
 | 
        
           |  |  | 1343 |     global $DB;
 | 
        
           |  |  | 1344 |   | 
        
           |  |  | 1345 |     $search = '';
 | 
        
           |  |  | 1346 |     $vals = array();
 | 
        
           |  |  | 1347 |     $fields = $DB->get_records('data_fields', array('dataid' => $data->id));
 | 
        
           |  |  | 1348 |   | 
        
           |  |  | 1349 |     if (!empty($fields)) {
 | 
        
           |  |  | 1350 |         foreach ($fields as $field) {
 | 
        
           |  |  | 1351 |             $searchfield = data_get_field_from_id($field->id, $data);
 | 
        
           |  |  | 1352 |             // Get field data to build search sql with.  If paging is false, get from user.
 | 
        
           |  |  | 1353 |             // If paging is true, get data from $searcharray which is obtained from the $SESSION (see line 116).
 | 
        
           |  |  | 1354 |             if (!$paging && $searchfield->type != 'unknown') {
 | 
        
           |  |  | 1355 |                 $val = $searchfield->parse_search_field($defaults);
 | 
        
           |  |  | 1356 |             } else {
 | 
        
           |  |  | 1357 |                 // Set value from session if there is a value @ the required index.
 | 
        
           |  |  | 1358 |                 if (isset($searcharray[$field->id])) {
 | 
        
           |  |  | 1359 |                     $val = $searcharray[$field->id]->data;
 | 
        
           |  |  | 1360 |                 } else { // If there is not an entry @ the required index, set value to blank.
 | 
        
           |  |  | 1361 |                     $val = '';
 | 
        
           |  |  | 1362 |                 }
 | 
        
           |  |  | 1363 |             }
 | 
        
           |  |  | 1364 |             if (!empty($val)) {
 | 
        
           |  |  | 1365 |                 $searcharray[$field->id] = new stdClass();
 | 
        
           |  |  | 1366 |                 list($searcharray[$field->id]->sql, $searcharray[$field->id]->params) = $searchfield->generate_sql('c'.$field->id, $val);
 | 
        
           |  |  | 1367 |                 $searcharray[$field->id]->data = $val;
 | 
        
           |  |  | 1368 |                 $vals[] = $val;
 | 
        
           |  |  | 1369 |             } else {
 | 
        
           |  |  | 1370 |                 // Clear it out.
 | 
        
           |  |  | 1371 |                 unset($searcharray[$field->id]);
 | 
        
           |  |  | 1372 |             }
 | 
        
           |  |  | 1373 |         }
 | 
        
           |  |  | 1374 |     }
 | 
        
           |  |  | 1375 |   | 
        
           |  |  | 1376 |     $rawtagnames = optional_param_array('tags', false, PARAM_TAGLIST);
 | 
        
           |  |  | 1377 |   | 
        
           |  |  | 1378 |     if ($rawtagnames) {
 | 
        
           |  |  | 1379 |         $searcharray[DATA_TAGS] = new stdClass();
 | 
        
           |  |  | 1380 |         $searcharray[DATA_TAGS]->params = [];
 | 
        
           |  |  | 1381 |         $searcharray[DATA_TAGS]->rawtagnames = $rawtagnames;
 | 
        
           |  |  | 1382 |         $searcharray[DATA_TAGS]->sql = '';
 | 
        
           |  |  | 1383 |     } else {
 | 
        
           |  |  | 1384 |         unset($searcharray[DATA_TAGS]);
 | 
        
           |  |  | 1385 |     }
 | 
        
           |  |  | 1386 |   | 
        
           |  |  | 1387 |     if (!$paging) {
 | 
        
           |  |  | 1388 |         // Name searching.
 | 
        
           |  |  | 1389 |         $fn = optional_param('u_fn', $fn, PARAM_NOTAGS);
 | 
        
           |  |  | 1390 |         $ln = optional_param('u_ln', $ln, PARAM_NOTAGS);
 | 
        
           |  |  | 1391 |     } else {
 | 
        
           |  |  | 1392 |         $fn = isset($searcharray[DATA_FIRSTNAME]) ? $searcharray[DATA_FIRSTNAME]->data : '';
 | 
        
           |  |  | 1393 |         $ln = isset($searcharray[DATA_LASTNAME]) ? $searcharray[DATA_LASTNAME]->data : '';
 | 
        
           |  |  | 1394 |     }
 | 
        
           |  |  | 1395 |     if (!empty($fn)) {
 | 
        
           |  |  | 1396 |         $searcharray[DATA_FIRSTNAME] = new stdClass();
 | 
        
           |  |  | 1397 |         $searcharray[DATA_FIRSTNAME]->sql    = '';
 | 
        
           |  |  | 1398 |         $searcharray[DATA_FIRSTNAME]->params = array();
 | 
        
           |  |  | 1399 |         $searcharray[DATA_FIRSTNAME]->field  = 'u.firstname';
 | 
        
           |  |  | 1400 |         $searcharray[DATA_FIRSTNAME]->data   = $fn;
 | 
        
           |  |  | 1401 |         $vals[] = $fn;
 | 
        
           |  |  | 1402 |     } else {
 | 
        
           |  |  | 1403 |         unset($searcharray[DATA_FIRSTNAME]);
 | 
        
           |  |  | 1404 |     }
 | 
        
           |  |  | 1405 |     if (!empty($ln)) {
 | 
        
           |  |  | 1406 |         $searcharray[DATA_LASTNAME] = new stdClass();
 | 
        
           |  |  | 1407 |         $searcharray[DATA_LASTNAME]->sql     = '';
 | 
        
           |  |  | 1408 |         $searcharray[DATA_LASTNAME]->params = array();
 | 
        
           |  |  | 1409 |         $searcharray[DATA_LASTNAME]->field   = 'u.lastname';
 | 
        
           |  |  | 1410 |         $searcharray[DATA_LASTNAME]->data    = $ln;
 | 
        
           |  |  | 1411 |         $vals[] = $ln;
 | 
        
           |  |  | 1412 |     } else {
 | 
        
           |  |  | 1413 |         unset($searcharray[DATA_LASTNAME]);
 | 
        
           |  |  | 1414 |     }
 | 
        
           |  |  | 1415 |   | 
        
           |  |  | 1416 |     // In case we want to switch to simple search later - there might be multiple values there ;-).
 | 
        
           |  |  | 1417 |     if ($vals) {
 | 
        
           |  |  | 1418 |         $val = reset($vals);
 | 
        
           |  |  | 1419 |         if (is_string($val)) {
 | 
        
           |  |  | 1420 |             $search = $val;
 | 
        
           |  |  | 1421 |         }
 | 
        
           |  |  | 1422 |     }
 | 
        
           |  |  | 1423 |     return [$searcharray, $search];
 | 
        
           |  |  | 1424 | }
 | 
        
           |  |  | 1425 |   | 
        
           |  |  | 1426 | /**
 | 
        
           |  |  | 1427 |  * Approves or unapproves an entry.
 | 
        
           |  |  | 1428 |  *
 | 
        
           |  |  | 1429 |  * @param  int $entryid the entry to approve or unapprove.
 | 
        
           |  |  | 1430 |  * @param  bool $approve Whether to approve or unapprove (true for approve false otherwise).
 | 
        
           |  |  | 1431 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1432 |  */
 | 
        
           |  |  | 1433 | function data_approve_entry($entryid, $approve) {
 | 
        
           |  |  | 1434 |     global $DB;
 | 
        
           |  |  | 1435 |   | 
        
           |  |  | 1436 |     $newrecord = new stdClass();
 | 
        
           |  |  | 1437 |     $newrecord->id = $entryid;
 | 
        
           |  |  | 1438 |     $newrecord->approved = $approve ? 1 : 0;
 | 
        
           |  |  | 1439 |     $DB->update_record('data_records', $newrecord);
 | 
        
           |  |  | 1440 | }
 | 
        
           |  |  | 1441 |   | 
        
           |  |  | 1442 | /**
 | 
        
           |  |  | 1443 |  * Populate the field contents of a new record with the submitted data.
 | 
        
           |  |  | 1444 |  * An event has been previously triggered upon the creation of the new record in data_add_record().
 | 
        
           |  |  | 1445 |  *
 | 
        
           |  |  | 1446 |  * @param  stdClass $data           database object
 | 
        
           |  |  | 1447 |  * @param  stdClass $context        context object
 | 
        
           |  |  | 1448 |  * @param  int $recordid            the new record id
 | 
        
           |  |  | 1449 |  * @param  array $fields            list of fields of the database
 | 
        
           |  |  | 1450 |  * @param  stdClass $datarecord     the submitted data
 | 
        
           |  |  | 1451 |  * @param  stdClass $processeddata  pre-processed submitted fields
 | 
        
           |  |  | 1452 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1453 |  */
 | 
        
           |  |  | 1454 | function data_add_fields_contents_to_new_record($data, $context, $recordid, $fields, $datarecord, $processeddata) {
 | 
        
           |  |  | 1455 |     global $DB;
 | 
        
           |  |  | 1456 |   | 
        
           |  |  | 1457 |     // Insert a whole lot of empty records to make sure we have them.
 | 
        
           |  |  | 1458 |     $records = array();
 | 
        
           |  |  | 1459 |     foreach ($fields as $field) {
 | 
        
           |  |  | 1460 |         $content = new stdClass();
 | 
        
           |  |  | 1461 |         $content->recordid = $recordid;
 | 
        
           |  |  | 1462 |         $content->fieldid = $field->id;
 | 
        
           |  |  | 1463 |         $records[] = $content;
 | 
        
           |  |  | 1464 |     }
 | 
        
           |  |  | 1465 |   | 
        
           |  |  | 1466 |     // Bulk insert the records now. Some records may have no data but all must exist.
 | 
        
           |  |  | 1467 |     $DB->insert_records('data_content', $records);
 | 
        
           |  |  | 1468 |   | 
        
           |  |  | 1469 |     // Add all provided content.
 | 
        
           |  |  | 1470 |     foreach ($processeddata->fields as $fieldname => $field) {
 | 
        
           |  |  | 1471 |         $field->update_content($recordid, $datarecord->$fieldname, $fieldname);
 | 
        
           |  |  | 1472 |     }
 | 
        
           |  |  | 1473 | }
 | 
        
           |  |  | 1474 |   | 
        
           |  |  | 1475 | /**
 | 
        
           |  |  | 1476 |  * Updates the fields contents of an existing record.
 | 
        
           |  |  | 1477 |  *
 | 
        
           |  |  | 1478 |  * @param  stdClass $data           database object
 | 
        
           |  |  | 1479 |  * @param  stdClass $record         record to update object
 | 
        
           |  |  | 1480 |  * @param  stdClass $context        context object
 | 
        
           |  |  | 1481 |  * @param  stdClass $datarecord     the submitted data
 | 
        
           |  |  | 1482 |  * @param  stdClass $processeddata  pre-processed submitted fields
 | 
        
           |  |  | 1483 |  * @since  Moodle 3.3
 | 
        
           |  |  | 1484 |  */
 | 
        
           |  |  | 1485 | function data_update_record_fields_contents($data, $record, $context, $datarecord, $processeddata) {
 | 
        
           |  |  | 1486 |     global $DB;
 | 
        
           |  |  | 1487 |   | 
        
           |  |  | 1488 |     // Reset the approved flag after edit if the user does not have permission to approve their own entries.
 | 
        
           |  |  | 1489 |     if (!has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 1490 |         $record->approved = 0;
 | 
        
           |  |  | 1491 |     }
 | 
        
           |  |  | 1492 |   | 
        
           |  |  | 1493 |     // Update the parent record.
 | 
        
           |  |  | 1494 |     $record->timemodified = time();
 | 
        
           |  |  | 1495 |     $DB->update_record('data_records', $record);
 | 
        
           |  |  | 1496 |   | 
        
           |  |  | 1497 |     // Update all content.
 | 
        
           |  |  | 1498 |     foreach ($processeddata->fields as $fieldname => $field) {
 | 
        
           |  |  | 1499 |         $field->update_content($record->id, $datarecord->$fieldname, $fieldname);
 | 
        
           |  |  | 1500 |     }
 | 
        
           |  |  | 1501 |   | 
        
           |  |  | 1502 |     // Trigger an event for updating this record.
 | 
        
           |  |  | 1503 |     $event = \mod_data\event\record_updated::create(array(
 | 
        
           |  |  | 1504 |         'objectid' => $record->id,
 | 
        
           |  |  | 1505 |         'context' => $context,
 | 
        
           |  |  | 1506 |         'courseid' => $data->course,
 | 
        
           |  |  | 1507 |         'other' => array(
 | 
        
           |  |  | 1508 |             'dataid' => $data->id
 | 
        
           |  |  | 1509 |         )
 | 
        
           |  |  | 1510 |     ));
 | 
        
           |  |  | 1511 |     $event->add_record_snapshot('data', $data);
 | 
        
           |  |  | 1512 |     $event->trigger();
 | 
        
           |  |  | 1513 | }
 |