diff --git a/lib/classes/user.php b/lib/classes/user.php
index 0593334241d..98a03f080ff 100644
--- a/lib/classes/user.php
+++ b/lib/classes/user.php
@@ -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;
+ }
+
}
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 7f98a71e89d..71b2d4e2abe 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -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);
}
/**
diff --git a/lib/tests/user_test.php b/lib/tests/user_test.php
index d99bb0564a3..2eac24a3233 100644
--- a/lib/tests/user_test.php
+++ b/lib/tests/user_test.php
@@ -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("JD",
+ $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("JDJohn Doe",
+ $OUTPUT->render(\core_user::get_profile_picture($user1, $context, $options)));
+
+ // Display profile picture with options, no link.
+ $options = ['link' => false];
+ $this->assertEquals("JD",
+ $OUTPUT->render(\core_user::get_profile_picture($user1, $context, $options)));
+ }
}
diff --git a/user/upgrade.txt b/user/upgrade.txt
index 2edf699e1c8..056679fa213 100644
--- a/user/upgrade.txt
+++ b/user/upgrade.txt
@@ -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`