MDL-77353 core_user: new functions

New functions:
    * `core_user::get_profile_picture` for retrieving user picture.
    * `core_user::get_profile_url` for retrieving profile url.
    * `core_user::get_fullname` for retrieving user full name.

Note: the context is not used as this stage. It will be used by "User Disguises" plugin, which will be implemented later.
This commit is contained in:
Nathan Nguyen
2023-05-24 13:05:02 +10:00
parent 2e1c6fd43e
commit f897ecd627
4 changed files with 288 additions and 93 deletions
+186
View File
@@ -1226,4 +1226,190 @@ class core_user {
};
return null;
}
/**
* Return full name depending on context.
* This function should be used for displaying purposes only as the details may not be the same as it is on database.
*
* @param stdClass $user the person to get details of.
* @param context|null $context The context will be used to determine the visibility of the user's full name.
* @param array $options can include: override - if true, will not use forced firstname/lastname settings
* @return string Full name of the user
*/
public static function get_fullname(stdClass $user, context $context = null, array $options = []): string {
global $CFG, $SESSION;
// Clone the user so that it does not mess up the original object.
$user = clone($user);
// Override options.
$override = $options["override"] ?? false;
if (!isset($user->firstname) && !isset($user->lastname)) {
return '';
}
// Get all of the name fields.
$allnames = \core_user\fields::get_name_fields();
if ($CFG->debugdeveloper) {
$missingfields = [];
foreach ($allnames as $allname) {
if (!property_exists($user, $allname)) {
$missingfields[] = $allname;
}
}
if (!empty($missingfields)) {
debugging('The following name fields are missing from the user object: ' . implode(', ', $missingfields));
}
}
if (!$override) {
if (!empty($CFG->forcefirstname)) {
$user->firstname = $CFG->forcefirstname;
}
if (!empty($CFG->forcelastname)) {
$user->lastname = $CFG->forcelastname;
}
}
if (!empty($SESSION->fullnamedisplay)) {
$CFG->fullnamedisplay = $SESSION->fullnamedisplay;
}
$template = null;
// If the fullnamedisplay setting is available, set the template to that.
if (isset($CFG->fullnamedisplay)) {
$template = $CFG->fullnamedisplay;
}
// If the template is empty, or set to language, return the language string.
if ((empty($template) || $template == 'language') && !$override) {
return get_string('fullnamedisplay', null, $user);
}
// Check to see if we are displaying according to the alternative full name format.
if ($override) {
if (empty($CFG->alternativefullnameformat) || $CFG->alternativefullnameformat == 'language') {
// Default to show just the user names according to the fullnamedisplay string.
return get_string('fullnamedisplay', null, $user);
} else {
// If the override is true, then change the template to use the complete name.
$template = $CFG->alternativefullnameformat;
}
}
$requirednames = array();
// With each name, see if it is in the display name template, and add it to the required names array if it is.
foreach ($allnames as $allname) {
if (strpos($template, $allname) !== false) {
$requirednames[] = $allname;
}
}
$displayname = $template;
// Switch in the actual data into the template.
foreach ($requirednames as $altname) {
if (isset($user->$altname)) {
// Using empty() on the below if statement causes breakages.
if ((string)$user->$altname == '') {
$displayname = str_replace($altname, 'EMPTY', $displayname);
} else {
$displayname = str_replace($altname, $user->$altname, $displayname);
}
} else {
$displayname = str_replace($altname, 'EMPTY', $displayname);
}
}
// Tidy up any misc. characters (Not perfect, but gets most characters).
// Don't remove the "u" at the end of the first expression unless you want garbled characters when combining hiragana or
// katakana and parenthesis.
$patterns = array();
// This regular expression replacement is to fix problems such as 'James () Kirk' Where 'Tiberius' (middlename) has not been
// filled in by a user.
// The special characters are Japanese brackets that are common enough to make allowances for them (not covered by :punct:).
$patterns[] = '/[[:punct:]「」]*EMPTY[[:punct:]「」]*/u';
// This regular expression is to remove any double spaces in the display name.
$patterns[] = '/\s{2,}/u';
foreach ($patterns as $pattern) {
$displayname = preg_replace($pattern, ' ', $displayname);
}
// Trimming $displayname will help the next check to ensure that we don't have a display name with spaces.
$displayname = trim($displayname);
if (empty($displayname)) {
// Going with just the first name if no alternate fields are filled out. May be changed later depending on what
// people in general feel is a good setting to fall back on.
$displayname = $user->firstname;
}
return $displayname;
}
/**
* Return profile url depending on context.
*
* @param stdClass $user the person to get details of.
* @param context|null $context The context will be used to determine the visibility of the user's profile url.
* @return moodle_url Profile url of the user
*/
public static function get_profile_url(stdClass $user, context $context = null): moodle_url {
if (empty($user->id)) {
throw new coding_exception('User id is required when displaying profile url.');
}
// Params to be passed to the user view page.
$params = ['id' => $user->id];
// Get courseid if provided.
if (isset($options['courseid'])) {
$params['courseid'] = $options['courseid'];
}
// Get courseid from context if provided.
if ($context) {
$coursecontext = $context->get_course_context(false);
if ($coursecontext) {
$params['courseid'] = $coursecontext->instanceid;
}
}
// If courseid is not set or is set to site id, then return profile page, otherwise return view page.
if (!isset($params['courseid']) || $params['courseid'] == SITEID) {
return new moodle_url('/user/profile.php', $params);
} else {
return new moodle_url('/user/view.php', $params);
}
}
/**
* Return user picture depending on context.
* This function should be used for displaying purposes only as the details may not be the same as it is on database.
*
* @param stdClass $user the person to get details of.
* @param context|null $context The context will be used to determine the visibility of the user's picture.
* @param array $options public properties of {@see user_picture} to be overridden
* - courseid = $this->page->course->id (course id of user profile in link)
* - size = 35 (size of image)
* - link = true (make image clickable - the link leads to user profile)
* - popup = false (open in popup)
* - alttext = true (add image alt attribute)
* - class = image class attribute (default 'userpicture')
* - visibletoscreenreaders = true (whether to be visible to screen readers)
* - includefullname = false (whether to include the user's full name together with the user picture)
* - includetoken = false (whether to use a token for authentication. True for current user, int value for other user id)
* @return user_picture User picture object
*/
public static function get_profile_picture(stdClass $user, context $context = null, array $options = []): user_picture {
// Create a new user picture object.
$userpicture = new user_picture($user);
// Override the user picture object with the options provided.
foreach ($options as $key => $value) {
if (property_exists($userpicture, $key)) {
$userpicture->$key = $value;
}
}
// Return the user picture.
return $userpicture;
}
}
+6 -93
View File
@@ -3595,103 +3595,16 @@ function ismoving($courseid) {
* @return string
*/
function fullname($user, $override=false) {
global $CFG, $SESSION;
// Note: We do not intend to deprecate this function any time soon as it is too widely used at this time.
// Uses of it should be updated to use the new API and pass updated arguments.
if (!isset($user->firstname) and !isset($user->lastname)) {
// Return an empty string if there is no user.
if (empty($user)) {
return '';
}
// Get all of the name fields.
$allnames = \core_user\fields::get_name_fields();
if ($CFG->debugdeveloper) {
foreach ($allnames as $allname) {
if (!property_exists($user, $allname)) {
// If all the user name fields are not set in the user object, then notify the programmer that it needs to be fixed.
debugging('You need to update your sql to include additional name fields in the user object.', DEBUG_DEVELOPER);
// Message has been sent, no point in sending the message multiple times.
break;
}
}
}
if (!$override) {
if (!empty($CFG->forcefirstname)) {
$user->firstname = $CFG->forcefirstname;
}
if (!empty($CFG->forcelastname)) {
$user->lastname = $CFG->forcelastname;
}
}
if (!empty($SESSION->fullnamedisplay)) {
$CFG->fullnamedisplay = $SESSION->fullnamedisplay;
}
$template = null;
// If the fullnamedisplay setting is available, set the template to that.
if (isset($CFG->fullnamedisplay)) {
$template = $CFG->fullnamedisplay;
}
// If the template is empty, or set to language, return the language string.
if ((empty($template) || $template == 'language') && !$override) {
return get_string('fullnamedisplay', null, $user);
}
// Check to see if we are displaying according to the alternative full name format.
if ($override) {
if (empty($CFG->alternativefullnameformat) || $CFG->alternativefullnameformat == 'language') {
// Default to show just the user names according to the fullnamedisplay string.
return get_string('fullnamedisplay', null, $user);
} else {
// If the override is true, then change the template to use the complete name.
$template = $CFG->alternativefullnameformat;
}
}
$requirednames = array();
// With each name, see if it is in the display name template, and add it to the required names array if it is.
foreach ($allnames as $allname) {
if (strpos($template, $allname) !== false) {
$requirednames[] = $allname;
}
}
$displayname = $template;
// Switch in the actual data into the template.
foreach ($requirednames as $altname) {
if (isset($user->$altname)) {
// Using empty() on the below if statement causes breakages.
if ((string)$user->$altname == '') {
$displayname = str_replace($altname, 'EMPTY', $displayname);
} else {
$displayname = str_replace($altname, $user->$altname, $displayname);
}
} else {
$displayname = str_replace($altname, 'EMPTY', $displayname);
}
}
// Tidy up any misc. characters (Not perfect, but gets most characters).
// Don't remove the "u" at the end of the first expression unless you want garbled characters when combining hiragana or
// katakana and parenthesis.
$patterns = array();
// This regular expression replacement is to fix problems such as 'James () Kirk' Where 'Tiberius' (middlename) has not been
// filled in by a user.
// The special characters are Japanese brackets that are common enough to make allowances for them (not covered by :punct:).
$patterns[] = '/[[:punct:]「」]*EMPTY[[:punct:]「」]*/u';
// This regular expression is to remove any double spaces in the display name.
$patterns[] = '/\s{2,}/u';
foreach ($patterns as $pattern) {
$displayname = preg_replace($pattern, ' ', $displayname);
}
// Trimming $displayname will help the next check to ensure that we don't have a display name with spaces.
$displayname = trim($displayname);
if (empty($displayname)) {
// Going with just the first name if no alternate fields are filled out. May be changed later depending on what
// people in general feel is a good setting to fall back on.
$displayname = $user->firstname;
}
return $displayname;
$options = ['override' => $override];
return core_user::get_fullname($user, null, $options);
}
/**
+91
View File
@@ -813,4 +813,95 @@ class user_test extends \advanced_testcase {
$this->assertFalse(\core_user::awaiting_action($admin));
$this->assertTrue(\core_user::awaiting_action($manager));
}
/**
* Test for function to get user details.
*
* @covers \core_user::get_fullname
*/
public function test_display_name() {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user(['firstname' => 'John', 'lastname' => 'Doe']);
$context = \context_system::instance();
// Show real name as the force names config are not set.
$this->assertEquals('John Doe', \core_user::get_fullname($user, $context));
// With override, still show real name.
$options = ['override' => true];
$this->assertEquals('John Doe', \core_user::get_fullname($user, $context, $options));
// Set the force names config.
set_config('forcefirstname', 'Bruce');
set_config('forcelastname', 'Simpson');
// Show forced names.
$this->assertEquals('Bruce Simpson', \core_user::get_fullname($user, $context));
// With override, show real name.
$options = ['override' => true];
$this->assertEquals('John Doe', \core_user::get_fullname($user, $context, $options));
}
/**
* Test for function to get user details.
*
* @covers \core_user::get_profile_url
*/
public function test_display_profile_url() {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user(['firstname' => 'John', 'lastname' => 'Doe']);
// Display profile url at site context.
$this->assertEquals("https://www.example.com/moodle/user/profile.php?id={$user->id}",
\core_user::get_profile_url($user)->out());
// Display profile url at course context.
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$this->assertEquals("https://www.example.com/moodle/user/view.php?id={$user->id}&courseid={$course->id}",
\core_user::get_profile_url($user, $coursecontext));
// Throw error if userid is invalid.
unset($user->id);
$this->expectException(\coding_exception::class);
$this->expectExceptionMessage('User id is required when displaying profile url.');
\core_user::get_profile_url($user, $coursecontext);
}
/**
* Test for function to get user details.
*
* @covers \core_user::get_profile_picture
*/
public function test_display_profile_picture() {
global $OUTPUT, $CFG;
$this->resetAfterTest();
$user1 = $this->getDataGenerator()->create_user(['firstname' => 'John', 'lastname' => 'Doe']);
$user2 = $this->getDataGenerator()->create_user(['picture' => 1]);
// Display profile picture.
$context = \context_system::instance();
// No image, show initials.
$this->assertStringContainsString("<span class=\"userinitials size-35\">JD</span></a>",
$OUTPUT->render(\core_user::get_profile_picture($user1, $context)));
// With Image.
$expectedimagesrc = $CFG->wwwroot . '/pluginfile.php/' . \context_user::instance($user2->id)->id .
'/user/icon/boost/f2?rev=1';
$this->assertStringContainsString($expectedimagesrc,
$OUTPUT->render(\core_user::get_profile_picture($user2, $context)));
// Display profile picture with options.
$options = ['size' => 50, 'includefullname' => true];
$this->assertStringContainsString("<span class=\"userinitials size-50\">JD</span>John Doe</a>",
$OUTPUT->render(\core_user::get_profile_picture($user1, $context, $options)));
// Display profile picture with options, no link.
$options = ['link' => false];
$this->assertEquals("<span class=\"userinitials size-35\">JD</span>",
$OUTPUT->render(\core_user::get_profile_picture($user1, $context, $options)));
}
}
+5
View File
@@ -2,6 +2,11 @@ This files describes API changes for code that uses the user API.
=== 4.3 ===
* Added new methods:
- `core_user::get_profile_picture` for retrieving user picture.
- `core_user::get_profile_url` for retrieving profile url.
- `core_user::get_fullname` for retrieving user full name.
* The following previously deprecated methods have been removed and can no longer be used:
- `profile_display_fields`
- `profile_edit_category`