Merge branch 'wip-MDL-60029-master' of git://github.com/marinaglancy/moodle

This commit is contained in:
Jun Pataleta 2017-10-12 16:16:42 +08:00
commit dab702d394
6 changed files with 223 additions and 170 deletions

View File

@ -367,19 +367,13 @@ function core_myprofile_navigation(core_user\output\myprofile\tree $tree, $user,
$tree->add_node($node);
}
if ($categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
foreach ($categories as $category) {
if ($fields = $DB->get_records('user_info_field', array('categoryid' => $category->id), 'sortorder ASC')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $user->id);
if ($formfield->is_visible() and !$formfield->is_empty()) {
$node = new core_user\output\myprofile\node('contact', 'custom_field_' . $formfield->field->shortname,
format_string($formfield->field->name), null, null, $formfield->display_data());
$tree->add_node($node);
}
}
$categories = profile_get_user_fields_with_data_by_category($user->id);
foreach ($categories as $categoryid => $fields) {
foreach ($fields as $formfield) {
if ($formfield->is_visible() and !$formfield->is_empty()) {
$node = new core_user\output\myprofile\node('contact', 'custom_field_' . $formfield->field->shortname,
format_string($formfield->field->name), null, null, $formfield->display_data());
$tree->add_node($node);
}
}
}

View File

@ -331,34 +331,28 @@ function user_get_user_details($user, $course = null, array $userfields = array(
$userdetails['fullname'] = fullname($user);
if (in_array('customfields', $userfields)) {
$fields = $DB->get_recordset_sql("SELECT f.*
FROM {user_info_field} f
JOIN {user_info_category} c
ON f.categoryid=c.id
ORDER BY c.sortorder ASC, f.sortorder ASC");
$categories = profile_get_user_fields_with_data_by_category($user->id);
$userdetails['customfields'] = array();
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $user->id);
if ($formfield->is_visible() and !$formfield->is_empty()) {
foreach ($categories as $categoryid => $fields) {
foreach ($fields as $formfield) {
if ($formfield->is_visible() and !$formfield->is_empty()) {
// TODO: Part of MDL-50728, this conditional coding must be moved to
// proper profile fields API so they are self-contained.
// We only use display_data in fields that require text formatting.
if ($field->datatype == 'text' or $field->datatype == 'textarea') {
$fieldvalue = $formfield->display_data();
} else {
// Cases: datetime, checkbox and menu.
$fieldvalue = $formfield->data;
// TODO: Part of MDL-50728, this conditional coding must be moved to
// proper profile fields API so they are self-contained.
// We only use display_data in fields that require text formatting.
if ($formfield->field->datatype == 'text' or $formfield->field->datatype == 'textarea') {
$fieldvalue = $formfield->display_data();
} else {
// Cases: datetime, checkbox and menu.
$fieldvalue = $formfield->data;
}
$userdetails['customfields'][] =
array('name' => $formfield->field->name, 'value' => $fieldvalue,
'type' => $formfield->field->datatype, 'shortname' => $formfield->field->shortname);
}
$userdetails['customfields'][] =
array('name' => $formfield->field->name, 'value' => $fieldvalue,
'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
}
}
$fields->close();
// Unset customfields if it's empty.
if (empty($userdetails['customfields'])) {
unset($userdetails['customfields']);

View File

@ -30,39 +30,6 @@
*/
class profile_field_checkbox extends profile_field_base {
/**
* Constructor method.
* Pulls out the options for the checkbox from the database and sets the
* the corresponding key for the data if it exists
*
* @param int $fieldid
* @param int $userid
*/
public function __construct($fieldid=0, $userid=0) {
global $DB;
// First call parent constructor.
parent::__construct($fieldid, $userid);
if (!empty($this->field)) {
$datafield = $DB->get_field('user_info_data', 'data', array('userid' => $this->userid, 'fieldid' => $this->fieldid));
if ($datafield !== false) {
$this->data = $datafield;
} else {
$this->data = $this->field->defaultdata;
}
}
}
/**
* Old syntax of class constructor. Deprecated in PHP7.
*
* @deprecated since Moodle 3.1
*/
public function profile_field_checkbox($fieldid=0, $userid=0) {
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
self::__construct($fieldid, $userid);
}
/**
* Add elements for editing the profile field value.
* @param moodleform $mform

View File

@ -43,10 +43,11 @@ class profile_field_menu extends profile_field_base {
*
* @param int $fieldid
* @param int $userid
* @param object $fielddata
*/
public function __construct($fieldid = 0, $userid = 0) {
public function __construct($fieldid = 0, $userid = 0, $fielddata = null) {
// First call parent constructor.
parent::__construct($fieldid, $userid);
parent::__construct($fieldid, $userid, $fielddata);
// Param 1 for menu type is the options.
if (isset($this->field->param1)) {
@ -73,16 +74,6 @@ class profile_field_menu extends profile_field_base {
}
}
/**
* Old syntax of class constructor. Deprecated in PHP7.
*
* @deprecated since Moodle 3.1
*/
public function profile_field_menu($fieldid=0, $userid=0) {
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
self::__construct($fieldid, $userid);
}
/**
* Create the code snippet for this field instance
* Overwrites the base class method

View File

@ -0,0 +1,6 @@
This files describes API changes in /user/profile/field/* - user profile fields,
information provided here is intended especially for developers.
=== 3.4 ===
* profile_field_base::__construct() now takes three arguments instead of two. Update your plugins if required.

View File

@ -56,17 +56,44 @@ class profile_field_base {
/** @var string */
public $dataformat;
/** @var string name of the user profile category */
protected $categoryname;
/**
* Constructor method.
* @param int $fieldid id of the profile from the user_info_field table
* @param int $userid id of the user for whom we are displaying data
* @param object $fielddata optional data for the field object plus additional fields 'hasuserdata', 'data' and 'dataformat'
* with user data. (If $fielddata->hasuserdata is empty, user data is not available and we should use default data).
* If this parameter is passed, constructor will not call load_data() at all.
*/
public function __construct($fieldid=0, $userid=0) {
global $USER;
public function __construct($fieldid=0, $userid=0, $fielddata=null) {
global $CFG;
if ($CFG->debugdeveloper) {
// In Moodle 3.4 the new argument $fielddata was added to the constructor. Make sure that
// plugin constructor properly passes this argument.
$backtrace = debug_backtrace();
if (isset($backtrace[1]['class']) && $backtrace[1]['function'] === '__construct' &&
in_array(self::class, class_parents($backtrace[1]['class']))) {
// If this constructor is called from the constructor of the plugin make sure that the third argument was passed through.
if (count($backtrace[1]['args']) >= 3 && count($backtrace[0]['args']) < 3) {
debugging($backtrace[1]['class'].'::__construct() must support $fielddata as the third argument ' .
'and pass it to the parent constructor', DEBUG_DEVELOPER);
}
}
}
$this->set_fieldid($fieldid);
$this->set_userid($userid);
$this->load_data();
if ($fielddata) {
$this->set_field($fielddata);
if ($userid && !empty($fielddata->hasuserdata)) {
$this->set_user_data($fielddata->data, $fielddata->dataformat);
}
} else {
$this->load_data();
}
}
/**
@ -288,9 +315,73 @@ class profile_field_base {
$this->fieldid = $fieldid;
}
/**
* Sets the field object and default data and format into $this->data and $this->dataformat
*
* This method should be called before {@link self::set_user_data}
*
* @param stdClass $field
* @throws coding_exception
*/
public function set_field($field) {
global $CFG;
if ($CFG->debugdeveloper) {
$properties = ['id', 'shortname', 'name', 'datatype', 'description', 'descriptionformat', 'categoryid', 'sortorder',
'required', 'locked', 'visible', 'forceunique', 'signup', 'defaultdata', 'defaultdataformat', 'param1', 'param2',
'param3', 'param4', 'param5'];
foreach ($properties as $property) {
if (!property_exists($field, $property)) {
debugging('The \'' . $property . '\' property must be set.', DEBUG_DEVELOPER);
}
}
}
if ($this->fieldid && $this->fieldid != $field->id) {
throw new coding_exception('Can not set field object after a different field id was set');
}
$this->fieldid = $field->id;
$this->field = $field;
$this->inputname = 'profile_field_' . $this->field->shortname;
$this->data = $this->field->defaultdata;
$this->dataformat = FORMAT_HTML;
}
/**
* Sets user id and user data for the field
*
* @param mixed $data
* @param int $dataformat
*/
public function set_user_data($data, $dataformat) {
$this->data = $data;
$this->dataformat = $dataformat;
}
/**
* Set the name for the profile category where this field is
*
* @param string $categoryname
*/
public function set_category_name($categoryname) {
$this->categoryname = $categoryname;
}
/**
* Returns the name of the profile category where this field is
*
* @return string
*/
public function get_category_name() {
global $DB;
if ($this->categoryname === null) {
$this->categoryname = $DB->get_field('user_info_category', 'name', ['id' => $this->field->categoryid]);
}
return $this->categoryname;
}
/**
* Accessor method: Load the field record and user data associated with the
* object's fieldid and userid
*
* @internal This method should not generally be overwritten by child classes.
*/
public function load_data() {
@ -301,18 +392,13 @@ class profile_field_base {
$this->field = null;
$this->inputname = '';
} else {
$this->field = $field;
$this->inputname = 'profile_field_'.$field->shortname;
$this->set_field($field);
}
if (!empty($this->field)) {
if (!empty($this->field) && $this->userid) {
$params = array('userid' => $this->userid, 'fieldid' => $this->fieldid);
if ($data = $DB->get_record('user_info_data', $params, 'data, dataformat')) {
$this->data = $data->data;
$this->dataformat = $data->dataformat;
} else {
$this->data = $this->field->defaultdata;
$this->dataformat = FORMAT_HTML;
$this->set_user_data($data->data, $data->dataformat);
}
} else {
$this->data = null;
@ -327,6 +413,8 @@ class profile_field_base {
public function is_visible() {
global $USER;
$context = $this->userid ? context_user::instance($this->userid) : context_system::instance();
switch ($this->field->visible) {
case PROFILE_VISIBLE_ALL:
return true;
@ -334,12 +422,10 @@ class profile_field_base {
if ($this->userid == $USER->id) {
return true;
} else {
return has_capability('moodle/user:viewalldetails',
context_user::instance($this->userid));
return has_capability('moodle/user:viewalldetails', $context);
}
default:
return has_capability('moodle/user:viewalldetails',
context_user::instance($this->userid));
return has_capability('moodle/user:viewalldetails', $context);
}
}
@ -411,20 +497,64 @@ class profile_field_base {
}
}
/**
* Returns an array of all custom field records with any defined data (or empty data), for the specified user id.
* @param int $userid
* @return profile_field_base[]
*/
function profile_get_user_fields_with_data($userid) {
global $DB, $CFG;
// Join any user info data present with each user info field for the user object.
$sql = 'SELECT uif.*, uic.name AS categoryname ';
if ($userid) {
$sql .= ', uid.id AS hasuserdata, uid.data, uid.dataformat ';
}
$sql .= 'FROM {user_info_field} uif ';
$sql .= 'LEFT JOIN {user_info_category} uic ON uif.categoryid = uic.id ';
if ($userid) {
$sql .= 'LEFT JOIN {user_info_data} uid ON uif.id = uid.fieldid AND uid.userid = :userid ';
}
$sql .= 'ORDER BY uic.sortorder ASC, uif.sortorder ASC ';
$fields = $DB->get_records_sql($sql, ['userid' => $userid]);
$data = [];
foreach ($fields as $field) {
require_once($CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php');
$classname = 'profile_field_' . $field->datatype;
$field->hasuserdata = !empty($field->hasuserdata);
/** @var profile_field_base $fieldobject */
$fieldobject = new $classname($field->id, $userid, $field);
$fieldobject->set_category_name($field->categoryname);
unset($field->categoryname);
$data[] = $fieldobject;
}
return $data;
}
/**
* Returns an array of all custom field records with any defined data (or empty data), for the specified user id, by category.
* @param int $userid
* @return profile_field_base[][]
*/
function profile_get_user_fields_with_data_by_category($userid) {
$fields = profile_get_user_fields_with_data($userid);
$data = [];
foreach ($fields as $field) {
$data[$field->field->categoryid][] = $field;
}
return $data;
}
/**
* Loads user profile field data into the user object.
* @param stdClass $user
*/
function profile_load_data($user) {
global $CFG, $DB;
global $CFG;
if ($fields = $DB->get_records('user_info_field')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $user->id);
$formfield->edit_load_user_data($user);
}
$fields = profile_get_user_fields_with_data($user->id);
foreach ($fields as $formfield) {
$formfield->edit_load_user_data($user);
}
}
@ -440,28 +570,21 @@ function profile_definition($mform, $userid = 0) {
// If user is "admin" fields are displayed regardless.
$update = has_capability('moodle/user:update', context_system::instance());
if ($categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
foreach ($categories as $category) {
if ($fields = $DB->get_records('user_info_field', array('categoryid' => $category->id), 'sortorder ASC')) {
$categories = profile_get_user_fields_with_data_by_category($userid);
foreach ($categories as $categoryid => $fields) {
// Check first if *any* fields will be displayed.
$display = false;
foreach ($fields as $formfield) {
if ($formfield->is_visible()) {
$display = true;
}
}
// Check first if *any* fields will be displayed.
$display = false;
foreach ($fields as $field) {
if ($field->visible != PROFILE_VISIBLE_NONE) {
$display = true;
}
}
// Display the header and the fields.
if ($display or $update) {
$mform->addElement('header', 'category_'.$category->id, format_string($category->name));
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $userid);
$formfield->edit_field($mform);
}
}
// Display the header and the fields.
if ($display or $update) {
$mform->addElement('header', 'category_'.$categoryid, format_string($formfield->get_category_name()));
foreach ($fields as $formfield) {
$formfield->edit_field($mform);
}
}
}
@ -473,17 +596,13 @@ function profile_definition($mform, $userid = 0) {
* @param int $userid
*/
function profile_definition_after_data($mform, $userid) {
global $CFG, $DB;
global $CFG;
$userid = ($userid < 0) ? 0 : (int)$userid;
if ($fields = $DB->get_records('user_info_field')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $userid);
$formfield->edit_after_data($mform);
}
$fields = profile_get_user_fields_with_data($userid);
foreach ($fields as $formfield) {
$formfield->edit_after_data($mform);
}
}
@ -494,16 +613,12 @@ function profile_definition_after_data($mform, $userid) {
* @return array
*/
function profile_validation($usernew, $files) {
global $CFG, $DB;
global $CFG;
$err = array();
if ($fields = $DB->get_records('user_info_field')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $usernew->id);
$err += $formfield->edit_validate_field($usernew, $files);
}
$fields = profile_get_user_fields_with_data($usernew->id);
foreach ($fields as $formfield) {
$err += $formfield->edit_validate_field($usernew, $files);
}
return $err;
}
@ -513,15 +628,11 @@ function profile_validation($usernew, $files) {
* @param stdClass $usernew
*/
function profile_save_data($usernew) {
global $CFG, $DB;
global $CFG;
if ($fields = $DB->get_records('user_info_field')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $usernew->id);
$formfield->edit_save_data($usernew);
}
$fields = profile_get_user_fields_with_data($usernew->id);
foreach ($fields as $formfield) {
$formfield->edit_save_data($usernew);
}
}
@ -532,18 +643,12 @@ function profile_save_data($usernew) {
function profile_display_fields($userid) {
global $CFG, $USER, $DB;
if ($categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
foreach ($categories as $category) {
if ($fields = $DB->get_records('user_info_field', array('categoryid' => $category->id), 'sortorder ASC')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $userid);
if ($formfield->is_visible() and !$formfield->is_empty()) {
echo html_writer::tag('dt', format_string($formfield->field->name));
echo html_writer::tag('dd', $formfield->display_data());
}
}
$categories = profile_get_user_fields_with_data_by_category($userid);
foreach ($categories as $categoryid => $fields) {
foreach ($fields as $formfield) {
if ($formfield->is_visible() and !$formfield->is_empty()) {
echo html_writer::tag('dt', format_string($formfield->field->name));
echo html_writer::tag('dd', $formfield->display_data());
}
}
}
@ -611,18 +716,14 @@ function profile_signup_fields($mform) {
* @return stdClass
*/
function profile_user_record($userid, $onlyinuserobject = true) {
global $CFG, $DB;
global $CFG;
$usercustomfields = new stdClass();
if ($fields = $DB->get_records('user_info_field')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $userid);
if (!$onlyinuserobject || $formfield->is_user_object_data()) {
$usercustomfields->{$field->shortname} = $formfield->data;
}
$fields = profile_get_user_fields_with_data($userid);
foreach ($fields as $formfield) {
if (!$onlyinuserobject || $formfield->is_user_object_data()) {
$usercustomfields->{$formfield->field->shortname} = $formfield->data;
}
}