Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Profile field API library file. 19 * 20 * @package core_user 21 * @copyright 2007 onwards Shane Elliot {@link http://pukunui.com} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 /** 26 * Visible to anyone who can view the user. 27 * Editable by the profile owner if they have the moodle/user:editownprofile capability 28 * or any user with the moodle/user:update capability. 29 */ 30 define('PROFILE_VISIBLE_ALL', '2'); 31 /** 32 * Visible to the profile owner or anyone with the moodle/user:viewalldetails capability. 33 * Editable by the profile owner if they have the moodle/user:editownprofile capability 34 * or any user with moodle/user:viewalldetails and moodle/user:update capabilities. 35 */ 36 define('PROFILE_VISIBLE_PRIVATE', '1'); 37 /** 38 * Only visible to users with the moodle/user:viewalldetails capability. 39 * Only editable by users with the moodle/user:viewalldetails and moodle/user:update capabilities. 40 */ 41 define('PROFILE_VISIBLE_NONE', '0'); 42 43 /** 44 * Base class for the customisable profile fields. 45 * 46 * @package core_user 47 * @copyright 2007 onwards Shane Elliot {@link http://pukunui.com} 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class profile_field_base { 51 52 // These 2 variables are really what we're interested in. 53 // Everything else can be extracted from them. 54 55 /** @var int */ 56 public $fieldid; 57 58 /** @var int */ 59 public $userid; 60 61 /** @var stdClass */ 62 public $field; 63 64 /** @var string */ 65 public $inputname; 66 67 /** @var mixed */ 68 public $data; 69 70 /** @var string */ 71 public $dataformat; 72 73 /** @var string name of the user profile category */ 74 protected $categoryname; 75 76 /** 77 * Constructor method. 78 * @param int $fieldid id of the profile from the user_info_field table 79 * @param int $userid id of the user for whom we are displaying data 80 * @param object $fielddata optional data for the field object plus additional fields 'hasuserdata', 'data' and 'dataformat' 81 * with user data. (If $fielddata->hasuserdata is empty, user data is not available and we should use default data). 82 * If this parameter is passed, constructor will not call load_data() at all. 83 */ 84 public function __construct($fieldid=0, $userid=0, $fielddata=null) { 85 global $CFG; 86 87 if ($CFG->debugdeveloper) { 88 // In Moodle 3.4 the new argument $fielddata was added to the constructor. Make sure that 89 // plugin constructor properly passes this argument. 90 $backtrace = debug_backtrace(); 91 if (isset($backtrace[1]['class']) && $backtrace[1]['function'] === '__construct' && 92 in_array(self::class, class_parents($backtrace[1]['class']))) { 93 // If this constructor is called from the constructor of the plugin make sure that the third argument was passed through. 94 if (count($backtrace[1]['args']) >= 3 && count($backtrace[0]['args']) < 3) { 95 debugging($backtrace[1]['class'].'::__construct() must support $fielddata as the third argument ' . 96 'and pass it to the parent constructor', DEBUG_DEVELOPER); 97 } 98 } 99 } 100 101 $this->set_fieldid($fieldid); 102 $this->set_userid($userid); 103 if ($fielddata) { 104 $this->set_field($fielddata); 105 if ($userid > 0 && !empty($fielddata->hasuserdata)) { 106 $this->set_user_data($fielddata->data, $fielddata->dataformat); 107 } 108 } else { 109 $this->load_data(); 110 } 111 } 112 113 /** 114 * Old syntax of class constructor. Deprecated in PHP7. 115 * 116 * @deprecated since Moodle 3.1 117 */ 118 public function profile_field_base($fieldid=0, $userid=0) { 119 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); 120 self::__construct($fieldid, $userid); 121 } 122 123 /** 124 * Abstract method: Adds the profile field to the moodle form class 125 * @abstract The following methods must be overwritten by child classes 126 * @param moodleform $mform instance of the moodleform class 127 */ 128 public function edit_field_add($mform) { 129 print_error('mustbeoveride', 'debug', '', 'edit_field_add'); 130 } 131 132 /** 133 * Display the data for this field 134 * @return string 135 */ 136 public function display_data() { 137 $options = new stdClass(); 138 $options->para = false; 139 return format_text($this->data, FORMAT_MOODLE, $options); 140 } 141 142 /** 143 * Print out the form field in the edit profile page 144 * @param moodleform $mform instance of the moodleform class 145 * @return bool 146 */ 147 public function edit_field($mform) { 148 if (!$this->is_editable()) { 149 return false; 150 } 151 152 $this->edit_field_add($mform); 153 $this->edit_field_set_default($mform); 154 $this->edit_field_set_required($mform); 155 return true; 156 } 157 158 /** 159 * Tweaks the edit form 160 * @param moodleform $mform instance of the moodleform class 161 * @return bool 162 */ 163 public function edit_after_data($mform) { 164 if (!$this->is_editable()) { 165 return false; 166 } 167 168 $this->edit_field_set_locked($mform); 169 return true; 170 } 171 172 /** 173 * Saves the data coming from form 174 * @param stdClass $usernew data coming from the form 175 * @return mixed returns data id if success of db insert/update, false on fail, 0 if not permitted 176 */ 177 public function edit_save_data($usernew) { 178 global $DB; 179 180 if (!isset($usernew->{$this->inputname})) { 181 // Field not present in form, probably locked and invisible - skip it. 182 return; 183 } 184 185 $data = new stdClass(); 186 187 $usernew->{$this->inputname} = $this->edit_save_data_preprocess($usernew->{$this->inputname}, $data); 188 if (!isset($usernew->{$this->inputname})) { 189 // Field cannot be set to null, set the default value. 190 $usernew->{$this->inputname} = $this->field->defaultdata; 191 } 192 193 $data->userid = $usernew->id; 194 $data->fieldid = $this->field->id; 195 $data->data = $usernew->{$this->inputname}; 196 197 if ($dataid = $DB->get_field('user_info_data', 'id', array('userid' => $data->userid, 'fieldid' => $data->fieldid))) { 198 $data->id = $dataid; 199 $DB->update_record('user_info_data', $data); 200 } else { 201 $DB->insert_record('user_info_data', $data); 202 } 203 } 204 205 /** 206 * Validate the form field from profile page 207 * 208 * @param stdClass $usernew 209 * @return string contains error message otherwise null 210 */ 211 public function edit_validate_field($usernew) { 212 global $DB; 213 214 $errors = array(); 215 // Get input value. 216 if (isset($usernew->{$this->inputname})) { 217 if (is_array($usernew->{$this->inputname}) && isset($usernew->{$this->inputname}['text'])) { 218 $value = $usernew->{$this->inputname}['text']; 219 } else { 220 $value = $usernew->{$this->inputname}; 221 } 222 } else { 223 $value = ''; 224 } 225 226 // Check for uniqueness of data if required. 227 if ($this->is_unique() && (($value !== '') || $this->is_required())) { 228 $data = $DB->get_records_sql(' 229 SELECT id, userid 230 FROM {user_info_data} 231 WHERE fieldid = ? 232 AND ' . $DB->sql_compare_text('data', 255) . ' = ' . $DB->sql_compare_text('?', 255), 233 array($this->field->id, $value)); 234 if ($data) { 235 $existing = false; 236 foreach ($data as $v) { 237 if ($v->userid == $usernew->id) { 238 $existing = true; 239 break; 240 } 241 } 242 if (!$existing) { 243 $errors[$this->inputname] = get_string('valuealreadyused'); 244 } 245 } 246 } 247 return $errors; 248 } 249 250 /** 251 * Sets the default data for the field in the form object 252 * @param moodleform $mform instance of the moodleform class 253 */ 254 public function edit_field_set_default($mform) { 255 if (!empty($this->field->defaultdata)) { 256 $mform->setDefault($this->inputname, $this->field->defaultdata); 257 } 258 } 259 260 /** 261 * Sets the required flag for the field in the form object 262 * 263 * @param moodleform $mform instance of the moodleform class 264 */ 265 public function edit_field_set_required($mform) { 266 global $USER; 267 if ($this->is_required() && ($this->userid == $USER->id || isguestuser())) { 268 $mform->addRule($this->inputname, get_string('required'), 'required', null, 'client'); 269 } 270 } 271 272 /** 273 * HardFreeze the field if locked. 274 * @param moodleform $mform instance of the moodleform class 275 */ 276 public function edit_field_set_locked($mform) { 277 if (!$mform->elementExists($this->inputname)) { 278 return; 279 } 280 if ($this->is_locked() and !has_capability('moodle/user:update', context_system::instance())) { 281 $mform->hardFreeze($this->inputname); 282 $mform->setConstant($this->inputname, $this->data); 283 } 284 } 285 286 /** 287 * Hook for child classess to process the data before it gets saved in database 288 * @param stdClass $data 289 * @param stdClass $datarecord The object that will be used to save the record 290 * @return mixed 291 */ 292 public function edit_save_data_preprocess($data, $datarecord) { 293 return $data; 294 } 295 296 /** 297 * Loads a user object with data for this field ready for the edit profile 298 * form 299 * @param stdClass $user a user object 300 */ 301 public function edit_load_user_data($user) { 302 if ($this->data !== null) { 303 $user->{$this->inputname} = $this->data; 304 } 305 } 306 307 /** 308 * Check if the field data should be loaded into the user object 309 * By default it is, but for field types where the data may be potentially 310 * large, the child class should override this and return false 311 * @return bool 312 */ 313 public function is_user_object_data() { 314 return true; 315 } 316 317 /** 318 * Accessor method: set the userid for this instance 319 * @internal This method should not generally be overwritten by child classes. 320 * @param integer $userid id from the user table 321 */ 322 public function set_userid($userid) { 323 $this->userid = $userid; 324 } 325 326 /** 327 * Accessor method: set the fieldid for this instance 328 * @internal This method should not generally be overwritten by child classes. 329 * @param integer $fieldid id from the user_info_field table 330 */ 331 public function set_fieldid($fieldid) { 332 $this->fieldid = $fieldid; 333 } 334 335 /** 336 * Sets the field object and default data and format into $this->data and $this->dataformat 337 * 338 * This method should be called before {@link self::set_user_data} 339 * 340 * @param stdClass $field 341 * @throws coding_exception 342 */ 343 public function set_field($field) { 344 global $CFG; 345 if ($CFG->debugdeveloper) { 346 $properties = ['id', 'shortname', 'name', 'datatype', 'description', 'descriptionformat', 'categoryid', 'sortorder', 347 'required', 'locked', 'visible', 'forceunique', 'signup', 'defaultdata', 'defaultdataformat', 'param1', 'param2', 348 'param3', 'param4', 'param5']; 349 foreach ($properties as $property) { 350 if (!property_exists($field, $property)) { 351 debugging('The \'' . $property . '\' property must be set.', DEBUG_DEVELOPER); 352 } 353 } 354 } 355 if ($this->fieldid && $this->fieldid != $field->id) { 356 throw new coding_exception('Can not set field object after a different field id was set'); 357 } 358 $this->fieldid = $field->id; 359 $this->field = $field; 360 $this->inputname = 'profile_field_' . $this->field->shortname; 361 $this->data = $this->field->defaultdata; 362 $this->dataformat = FORMAT_HTML; 363 } 364 365 /** 366 * Sets user id and user data for the field 367 * 368 * @param mixed $data 369 * @param int $dataformat 370 */ 371 public function set_user_data($data, $dataformat) { 372 $this->data = $data; 373 $this->dataformat = $dataformat; 374 } 375 376 /** 377 * Set the name for the profile category where this field is 378 * 379 * @param string $categoryname 380 */ 381 public function set_category_name($categoryname) { 382 $this->categoryname = $categoryname; 383 } 384 385 /** 386 * Returns the name of the profile category where this field is 387 * 388 * @return string 389 */ 390 public function get_category_name() { 391 global $DB; 392 if ($this->categoryname === null) { 393 $this->categoryname = $DB->get_field('user_info_category', 'name', ['id' => $this->field->categoryid]); 394 } 395 return $this->categoryname; 396 } 397 398 /** 399 * Accessor method: Load the field record and user data associated with the 400 * object's fieldid and userid 401 * 402 * @internal This method should not generally be overwritten by child classes. 403 */ 404 public function load_data() { 405 global $DB; 406 407 // Load the field object. 408 if (($this->fieldid == 0) or (!($field = $DB->get_record('user_info_field', array('id' => $this->fieldid))))) { 409 $this->field = null; 410 $this->inputname = ''; 411 } else { 412 $this->set_field($field); 413 } 414 415 if (!empty($this->field) && $this->userid > 0) { 416 $params = array('userid' => $this->userid, 'fieldid' => $this->fieldid); 417 if ($data = $DB->get_record('user_info_data', $params, 'data, dataformat')) { 418 $this->set_user_data($data->data, $data->dataformat); 419 } 420 } else { 421 $this->data = null; 422 } 423 } 424 425 /** 426 * Check if the field data is visible to the current user 427 * @internal This method should not generally be overwritten by child classes. 428 * @return bool 429 */ 430 public function is_visible() { 431 global $USER; 432 433 $context = ($this->userid > 0) ? context_user::instance($this->userid) : context_system::instance(); 434 435 switch ($this->field->visible) { 436 case PROFILE_VISIBLE_ALL: 437 return true; 438 case PROFILE_VISIBLE_PRIVATE: 439 if ($this->is_signup_field() && (empty($this->userid) || isguestuser($this->userid))) { 440 return true; 441 } else if ($this->userid == $USER->id) { 442 return true; 443 } else { 444 return has_capability('moodle/user:viewalldetails', $context); 445 } 446 default: 447 return has_capability('moodle/user:viewalldetails', $context); 448 } 449 } 450 451 /** 452 * Check if the field data is editable for the current user 453 * This method should not generally be overwritten by child classes. 454 * @return bool 455 */ 456 public function is_editable() { 457 global $USER; 458 459 if (!$this->is_visible()) { 460 return false; 461 } 462 463 if ($this->is_signup_field() && (empty($this->userid) || isguestuser($this->userid))) { 464 // Allow editing the field on the signup page. 465 return true; 466 } 467 468 $systemcontext = context_system::instance(); 469 470 if ($this->userid == $USER->id && has_capability('moodle/user:editownprofile', $systemcontext)) { 471 return true; 472 } 473 474 if (has_capability('moodle/user:update', $systemcontext)) { 475 return true; 476 } 477 478 return false; 479 } 480 481 /** 482 * Check if the field data is considered empty 483 * @internal This method should not generally be overwritten by child classes. 484 * @return boolean 485 */ 486 public function is_empty() { 487 return ( ($this->data != '0') and empty($this->data)); 488 } 489 490 /** 491 * Check if the field is required on the edit profile page 492 * @internal This method should not generally be overwritten by child classes. 493 * @return bool 494 */ 495 public function is_required() { 496 return (boolean)$this->field->required; 497 } 498 499 /** 500 * Check if the field is locked on the edit profile page 501 * @internal This method should not generally be overwritten by child classes. 502 * @return bool 503 */ 504 public function is_locked() { 505 return (boolean)$this->field->locked; 506 } 507 508 /** 509 * Check if the field data should be unique 510 * @internal This method should not generally be overwritten by child classes. 511 * @return bool 512 */ 513 public function is_unique() { 514 return (boolean)$this->field->forceunique; 515 } 516 517 /** 518 * Check if the field should appear on the signup page 519 * @internal This method should not generally be overwritten by child classes. 520 * @return bool 521 */ 522 public function is_signup_field() { 523 return (boolean)$this->field->signup; 524 } 525 526 /** 527 * Return the field settings suitable to be exported via an external function. 528 * By default it return all the field settings. 529 * 530 * @return array all the settings 531 * @since Moodle 3.2 532 */ 533 public function get_field_config_for_external() { 534 return (array) $this->field; 535 } 536 537 /** 538 * Return the field type and null properties. 539 * This will be used for validating the data submitted by a user. 540 * 541 * @return array the param type and null property 542 * @since Moodle 3.2 543 */ 544 public function get_field_properties() { 545 return array(PARAM_RAW, NULL_NOT_ALLOWED); 546 } 547 } 548 549 /** 550 * Returns an array of all custom field records with any defined data (or empty data), for the specified user id. 551 * @param int $userid 552 * @return profile_field_base[] 553 */ 554 function profile_get_user_fields_with_data($userid) { 555 global $DB, $CFG; 556 557 // Join any user info data present with each user info field for the user object. 558 $sql = 'SELECT uif.*, uic.name AS categoryname '; 559 if ($userid > 0) { 560 $sql .= ', uind.id AS hasuserdata, uind.data, uind.dataformat '; 561 } 562 $sql .= 'FROM {user_info_field} uif '; 563 $sql .= 'LEFT JOIN {user_info_category} uic ON uif.categoryid = uic.id '; 564 if ($userid > 0) { 565 $sql .= 'LEFT JOIN {user_info_data} uind ON uif.id = uind.fieldid AND uind.userid = :userid '; 566 } 567 $sql .= 'ORDER BY uic.sortorder ASC, uif.sortorder ASC '; 568 $fields = $DB->get_records_sql($sql, ['userid' => $userid]); 569 $data = []; 570 foreach ($fields as $field) { 571 require_once($CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php'); 572 $classname = 'profile_field_' . $field->datatype; 573 $field->hasuserdata = !empty($field->hasuserdata); 574 /** @var profile_field_base $fieldobject */ 575 $fieldobject = new $classname($field->id, $userid, $field); 576 $fieldobject->set_category_name($field->categoryname); 577 unset($field->categoryname); 578 $data[] = $fieldobject; 579 } 580 return $data; 581 } 582 583 /** 584 * Returns an array of all custom field records with any defined data (or empty data), for the specified user id, by category. 585 * @param int $userid 586 * @return profile_field_base[][] 587 */ 588 function profile_get_user_fields_with_data_by_category($userid) { 589 $fields = profile_get_user_fields_with_data($userid); 590 $data = []; 591 foreach ($fields as $field) { 592 $data[$field->field->categoryid][] = $field; 593 } 594 return $data; 595 } 596 597 /** 598 * Loads user profile field data into the user object. 599 * @param stdClass $user 600 */ 601 function profile_load_data($user) { 602 global $CFG; 603 604 $fields = profile_get_user_fields_with_data($user->id); 605 foreach ($fields as $formfield) { 606 $formfield->edit_load_user_data($user); 607 } 608 } 609 610 /** 611 * Print out the customisable categories and fields for a users profile 612 * 613 * @param moodleform $mform instance of the moodleform class 614 * @param int $userid id of user whose profile is being edited. 615 */ 616 function profile_definition($mform, $userid = 0) { 617 $categories = profile_get_user_fields_with_data_by_category($userid); 618 foreach ($categories as $categoryid => $fields) { 619 // Check first if *any* fields will be displayed. 620 $fieldstodisplay = []; 621 622 foreach ($fields as $formfield) { 623 if ($formfield->is_editable()) { 624 $fieldstodisplay[] = $formfield; 625 } 626 } 627 628 if (empty($fieldstodisplay)) { 629 continue; 630 } 631 632 // Display the header and the fields. 633 $mform->addElement('header', 'category_'.$categoryid, format_string($fields[0]->get_category_name())); 634 foreach ($fieldstodisplay as $formfield) { 635 $formfield->edit_field($mform); 636 } 637 } 638 } 639 640 /** 641 * Adds profile fields to user edit forms. 642 * @param moodleform $mform 643 * @param int $userid 644 */ 645 function profile_definition_after_data($mform, $userid) { 646 global $CFG; 647 648 $userid = ($userid < 0) ? 0 : (int)$userid; 649 650 $fields = profile_get_user_fields_with_data($userid); 651 foreach ($fields as $formfield) { 652 $formfield->edit_after_data($mform); 653 } 654 } 655 656 /** 657 * Validates profile data. 658 * @param stdClass $usernew 659 * @param array $files 660 * @return array 661 */ 662 function profile_validation($usernew, $files) { 663 global $CFG; 664 665 $err = array(); 666 $fields = profile_get_user_fields_with_data($usernew->id); 667 foreach ($fields as $formfield) { 668 $err += $formfield->edit_validate_field($usernew, $files); 669 } 670 return $err; 671 } 672 673 /** 674 * Saves profile data for a user. 675 * @param stdClass $usernew 676 */ 677 function profile_save_data($usernew) { 678 global $CFG; 679 680 $fields = profile_get_user_fields_with_data($usernew->id); 681 foreach ($fields as $formfield) { 682 $formfield->edit_save_data($usernew); 683 } 684 } 685 686 /** 687 * Display profile fields. 688 * @param int $userid 689 */ 690 function profile_display_fields($userid) { 691 global $CFG, $USER, $DB; 692 693 $categories = profile_get_user_fields_with_data_by_category($userid); 694 foreach ($categories as $categoryid => $fields) { 695 foreach ($fields as $formfield) { 696 if ($formfield->is_visible() and !$formfield->is_empty()) { 697 echo html_writer::tag('dt', format_string($formfield->field->name)); 698 echo html_writer::tag('dd', $formfield->display_data()); 699 } 700 } 701 } 702 } 703 704 /** 705 * Retrieves a list of profile fields that must be displayed in the sign-up form. 706 * 707 * @return array list of profile fields info 708 * @since Moodle 3.2 709 */ 710 function profile_get_signup_fields() { 711 global $CFG, $DB; 712 713 $profilefields = array(); 714 // Only retrieve required custom fields (with category information) 715 // results are sort by categories, then by fields. 716 $sql = "SELECT uf.id as fieldid, ic.id as categoryid, ic.name as categoryname, uf.datatype 717 FROM {user_info_field} uf 718 JOIN {user_info_category} ic 719 ON uf.categoryid = ic.id AND uf.signup = 1 AND uf.visible<>0 720 ORDER BY ic.sortorder ASC, uf.sortorder ASC"; 721 722 if ($fields = $DB->get_records_sql($sql)) { 723 foreach ($fields as $field) { 724 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php'); 725 $newfield = 'profile_field_'.$field->datatype; 726 $fieldobject = new $newfield($field->fieldid); 727 728 $profilefields[] = (object) array( 729 'categoryid' => $field->categoryid, 730 'categoryname' => $field->categoryname, 731 'fieldid' => $field->fieldid, 732 'datatype' => $field->datatype, 733 'object' => $fieldobject 734 ); 735 } 736 } 737 return $profilefields; 738 } 739 740 /** 741 * Adds code snippet to a moodle form object for custom profile fields that 742 * should appear on the signup page 743 * @param moodleform $mform moodle form object 744 */ 745 function profile_signup_fields($mform) { 746 747 if ($fields = profile_get_signup_fields()) { 748 foreach ($fields as $field) { 749 // Check if we change the categories. 750 if (!isset($currentcat) || $currentcat != $field->categoryid) { 751 $currentcat = $field->categoryid; 752 $mform->addElement('header', 'category_'.$field->categoryid, format_string($field->categoryname)); 753 }; 754 $field->object->edit_field($mform); 755 } 756 } 757 } 758 759 /** 760 * Returns an object with the custom profile fields set for the given user 761 * @param integer $userid 762 * @param bool $onlyinuserobject True if you only want the ones in $USER. 763 * @return stdClass 764 */ 765 function profile_user_record($userid, $onlyinuserobject = true) { 766 global $CFG; 767 768 $usercustomfields = new stdClass(); 769 770 $fields = profile_get_user_fields_with_data($userid); 771 foreach ($fields as $formfield) { 772 if (!$onlyinuserobject || $formfield->is_user_object_data()) { 773 $usercustomfields->{$formfield->field->shortname} = $formfield->data; 774 } 775 } 776 777 return $usercustomfields; 778 } 779 780 /** 781 * Obtains a list of all available custom profile fields, indexed by id. 782 * 783 * Some profile fields are not included in the user object data (see 784 * profile_user_record function above). Optionally, you can obtain only those 785 * fields that are included in the user object. 786 * 787 * To be clear, this function returns the available fields, and does not 788 * return the field values for a particular user. 789 * 790 * @param bool $onlyinuserobject True if you only want the ones in $USER 791 * @return array Array of field objects from database (indexed by id) 792 * @since Moodle 2.7.1 793 */ 794 function profile_get_custom_fields($onlyinuserobject = false) { 795 global $DB, $CFG; 796 797 // Get all the fields. 798 $fields = $DB->get_records('user_info_field', null, 'id ASC'); 799 800 // If only doing the user object ones, unset the rest. 801 if ($onlyinuserobject) { 802 foreach ($fields as $id => $field) { 803 require_once($CFG->dirroot . '/user/profile/field/' . 804 $field->datatype . '/field.class.php'); 805 $newfield = 'profile_field_' . $field->datatype; 806 $formfield = new $newfield(); 807 if (!$formfield->is_user_object_data()) { 808 unset($fields[$id]); 809 } 810 } 811 } 812 813 return $fields; 814 } 815 816 /** 817 * Load custom profile fields into user object 818 * 819 * @param stdClass $user user object 820 */ 821 function profile_load_custom_fields($user) { 822 $user->profile = (array)profile_user_record($user->id); 823 } 824 825 /** 826 * Save custom profile fields for a user. 827 * 828 * @param int $userid The user id 829 * @param array $profilefields The fields to save 830 */ 831 function profile_save_custom_fields($userid, $profilefields) { 832 global $DB; 833 834 if ($fields = $DB->get_records('user_info_field')) { 835 foreach ($fields as $field) { 836 if (isset($profilefields[$field->shortname])) { 837 $conditions = array('fieldid' => $field->id, 'userid' => $userid); 838 $id = $DB->get_field('user_info_data', 'id', $conditions); 839 $data = $profilefields[$field->shortname]; 840 if ($id) { 841 $DB->set_field('user_info_data', 'data', $data, array('id' => $id)); 842 } else { 843 $record = array('fieldid' => $field->id, 'userid' => $userid, 'data' => $data); 844 $DB->insert_record('user_info_data', $record); 845 } 846 } 847 } 848 } 849 } 850 851 /** 852 * Trigger a user profile viewed event. 853 * 854 * @param stdClass $user user object 855 * @param stdClass $context context object (course or user) 856 * @param stdClass $course course object 857 * @since Moodle 2.9 858 */ 859 function profile_view($user, $context, $course = null) { 860 861 $eventdata = array( 862 'objectid' => $user->id, 863 'relateduserid' => $user->id, 864 'context' => $context 865 ); 866 867 if (!empty($course)) { 868 $eventdata['courseid'] = $course->id; 869 $eventdata['other'] = array( 870 'courseid' => $course->id, 871 'courseshortname' => $course->shortname, 872 'coursefullname' => $course->fullname 873 ); 874 } 875 876 $event = \core\event\user_profile_viewed::create($eventdata); 877 $event->add_record_snapshot('user', $user); 878 $event->trigger(); 879 } 880 881 /** 882 * Does the user have all required custom fields set? 883 * 884 * Internal, to be exclusively used by {@link user_not_fully_set_up()} only. 885 * 886 * Note that if users have no way to fill a required field via editing their 887 * profiles (e.g. the field is not visible or it is locked), we still return true. 888 * So this is actually checking if we should redirect the user to edit their 889 * profile, rather than whether there is a value in the database. 890 * 891 * @param int $userid 892 * @return bool 893 */ 894 function profile_has_required_custom_fields_set($userid) { 895 global $DB; 896 897 $sql = "SELECT f.id 898 FROM {user_info_field} f 899 LEFT JOIN {user_info_data} d ON (d.fieldid = f.id AND d.userid = ?) 900 WHERE f.required = 1 AND f.visible > 0 AND f.locked = 0 AND d.id IS NULL"; 901 902 if ($DB->record_exists_sql($sql, [$userid])) { 903 return false; 904 } 905 906 return true; 907 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body