Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

User fields: Difference between revisions

From MoodleDocs
m (Stronk7 moved page User fields API to User fields: removing the api suffix as requested)
m (Text replacement - "<code php>" to "<syntaxhighlight lang="php">")
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Moodle 3.11}}
{{Moodle 3.11}}


Code relating to display of user fields is in the class <tt>\core\user_fields</tt> in file <tt>/lib/classes/user_fields.php</tt>.
Code relating to display of user fields is in the class <tt>\core_user\fields</tt> in file <tt>/user/classes/fields.php</tt>.


* See also [[User-related APIs]], which has information about defining custom user fields.
* See also [[User-related APIs]], which has information about defining custom user fields.
Line 25: Line 25:
=== List fields required to display a user picture ===
=== List fields required to display a user picture ===


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_userpic()->get_required_fields();
$fields = \core_user\fields::for_userpic()->get_required_fields();
</code>
</syntaxhighlight>


This will return an array of fields required for displaying userpic (id, picture, firstname, lastname, ...).
This will return an array of fields required for displaying userpic (id, picture, firstname, lastname, ...).
Line 35: Line 35:
=== List fields required to display a user's full name ===
=== List fields required to display a user's full name ===


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_name()->get_required_fields();
$fields = \core_user\fields::for_name()->get_required_fields();
</code>
</syntaxhighlight>


This returns all fields needed to display a name (firstname, lastname, firstnamephonetic, ...).  
This returns all fields needed to display a name (firstname, lastname, firstnamephonetic, ...).  
Line 45: Line 45:
=== List fields required to display a user picture and full name ===
=== List fields required to display a user picture and full name ===


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_name()->with_userpic()->get_required_fields();
$fields = \core_user\fields::for_name()->with_userpic()->get_required_fields();
</code>
</syntaxhighlight>


If you need both types of fields, you can combine them by creating the object initially with a 'for' method, and then calling the 'with'  method to add a different category of fields.
If you need both types of fields, you can combine them by creating the object initially with a 'for' method, and then calling the 'with'  method to add a different category of fields.
Line 57: Line 57:
Because the capability for the current user depends on the location you are looking at, you need to pass a context when getting these fields.
Because the capability for the current user depends on the location you are looking at, you need to pass a context when getting these fields.


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_identity($context)->get_required_fields();
$fields = \core_user\fields::for_identity($context)->get_required_fields();
</code>
</syntaxhighlight>


The list of fields from this function might include custom profile fields e.g. 'profile_field_frog'. In legacy code which only supports fields on the user table, you can pass false to the second 'allow custom fields' parameter of the function:
The list of fields from this function might include custom profile fields e.g. 'profile_field_frog'. In legacy code which only supports fields on the user table, you can pass false to the second 'allow custom fields' parameter of the function:


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_identity($context, false)->get_required_fields();
$fields = \core_user\fields::for_identity($context, false)->get_required_fields();
</code>
</syntaxhighlight>


Now it won't return any custom profile fields (and your code doesn't support them, which is sad).
Now it won't return any custom profile fields (and your code doesn't support them, which is sad).
Line 73: Line 73:
Sometimes you might want a list of fields to contain extra fields. You could just add them to the array, but that could cause duplicates in some situations which might result in bugs that only appear in certain settings. Instead, there is a convenient way to include them in these lists:
Sometimes you might want a list of fields to contain extra fields. You could just add them to the array, but that could cause duplicates in some situations which might result in bugs that only appear in certain settings. Instead, there is a convenient way to include them in these lists:


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_identity($context)->including('email')->get_required_fields();
$fields = \core_user\fields::for_identity($context)->including('email')->get_required_fields();
</code>
</syntaxhighlight>


Alternatively you might want to exclude a field - this would usually be because you know you are going to list that field in a database query separately. It is OK to exclude a field whether or not it is actually included; that way the code will continue to work whatever the field list.
Alternatively you might want to exclude a field - this would usually be because you know you are going to list that field in a database query separately. It is OK to exclude a field whether or not it is actually included; that way the code will continue to work whatever the field list.


<code php>
<syntaxhighlight lang="php">
$fields = \core\user_fields::for_name()->excluding('firstname')->get_required_fields();
$fields = \core_user\fields::for_name()->excluding('firstname')->get_required_fields();
</code>
</syntaxhighlight>


You can use both including and excluding functions if you want.
You can use both including and excluding functions if you want.
Line 91: Line 91:
Let's use a simple example - we are writing code that displays a list of all users in the whole system ordered by their last access date, most recent first. For some reason we are also including deleted users (but maybe we're going to display them differently). Here is a basic SQL query that does this:
Let's use a simple example - we are writing code that displays a list of all users in the whole system ordered by their last access date, most recent first. For some reason we are also including deleted users (but maybe we're going to display them differently). Here is a basic SQL query that does this:


<code php>
<syntaxhighlight lang="php">
$result = $DB->get_records_sql("
$result = $DB->get_records_sql("
         SELECT u.id, u.deleted
         SELECT u.id, u.deleted
           FROM {user} u
           FROM {user} u
       ORDER BY u.lastaccess DESC", [], 0, 10);
       ORDER BY u.lastaccess DESC", [], 0, 10);
</code>
</syntaxhighlight>


Suppose that we also want to include the user's name, and any identity fields that are enabled for the current user. We don't want to include the 'id' or 'deleted' field because they're already included in the query.
Suppose that we also want to include the user's name, and any identity fields that are enabled for the current user. We don't want to include the 'id' or 'deleted' field because they're already included in the query.
Line 102: Line 102:
We can create a user fields object like this:
We can create a user fields object like this:


<code php>
<syntaxhighlight lang="php">
$context = \context_system::instance();
$context = \context_system::instance();
$userfields = \core\user_fields::for_name()->with_identity($context)->excluding('id', 'deleted');
$userfields = \core_user\fields::for_name()->with_identity($context)->excluding('id', 'deleted');
</code>
</syntaxhighlight>


The user fields object can create SQL snippets for you like this:
The user fields object can create SQL snippets for you like this:


<code php>
<syntaxhighlight lang="php">
$sql = $userfields->get_sql('u');
$sql = $userfields->get_sql('u');
</code>
</syntaxhighlight>


This returns an object with the fields 'selects', 'joins', 'params', and (not normally needed) 'mappings'. Here is how you use it with the above SQL query:
This returns an object with the fields 'selects', 'joins', 'params', and (not normally needed) 'mappings'. Here is how you use it with the above SQL query:


<code php>
<syntaxhighlight lang="php">
$result = $DB->get_records_sql("
$result = $DB->get_records_sql("
         SELECT u.id, u.deleted {$sql->selects}
         SELECT u.id, u.deleted {$sql->selects}
Line 121: Line 121:
               {$sql->joins}
               {$sql->joins}
       ORDER BY u.lastaccess DESC", $sql->params, 0, 10);
       ORDER BY u.lastaccess DESC", $sql->params, 0, 10);
</code>
</syntaxhighlight>


There are many options to the get_sql function, as well as the user table alias shown. For example, you can:
There are many options to the get_sql function, as well as the user table alias shown. For example, you can:
Line 138: Line 138:
An extra parameter on get_required_fields lets you include only one category of fields from the object:
An extra parameter on get_required_fields lets you include only one category of fields from the object:


<code php>
<syntaxhighlight lang="php">
$extracolumns = $userfields->get_required_fields([\core\user_fields::PURPOSE_IDENTITY]);
$extracolumns = $userfields->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
</code>
</syntaxhighlight>


== Field names ==
== Field names ==
Line 146: Line 146:
To display those columns you will need a header with a field name. You can get a field name as follows:
To display those columns you will need a header with a field name. You can get a field name as follows:


<code php>
<syntaxhighlight lang="php">
$header = \core\user_fields::get_display_name($field);
$header = \core_user\fields::get_display_name($field);
</code>
</syntaxhighlight>


This works for both standard user table fields e.g. email (it will get the appropriate language string), and for custom fields (it will get the name for the custom field).
This works for both standard user table fields e.g. email (it will get the appropriate language string), and for custom fields (it will get the name for the custom field).

Latest revision as of 20:35, 14 July 2021

Moodle 3.11


Code relating to display of user fields is in the class \core_user\fields in file /user/classes/fields.php.

Overview

This class is normally used when displaying lists of users in a table. It has the following main functions.

  1. Decide which extra user fields (e.g. email, username) should be shown in the table, based on the showuseridentity admin setting, the current context, and the permissions of the user.
  2. Provide lists of fields required for showing user picture or full name.
  3. Provide SQL that can be used within a query to get that information for users.

Custom fields

This class supports two kinds of fields: basic user fields (in the user table) and custom profile fields (in the user_info_data table). Because the queries are more complex when getting custom profile fields, there may be some code that doesn't support custom profile fields.

When fields are listed, a standard field in the user table such as email is called email. A custom profile field, such as one with the shortname frog, is prefixed so that it is referred to as profile_field_frog.

Listing fields

The following examples describe how you can get a list of user fields for a certain situation.

List fields required to display a user picture

$fields = \core_user\fields::for_userpic()->get_required_fields();

This will return an array of fields required for displaying userpic (id, picture, firstname, lastname, ...).

These are the fields you need to have in the user object in order to call the $OUTPUT->user_picture($user) function.

List fields required to display a user's full name

$fields = \core_user\fields::for_name()->get_required_fields();

This returns all fields needed to display a name (firstname, lastname, firstnamephonetic, ...).

These are the fields you need to have in the user object in order to call the fullname($user) function.

List fields required to display a user picture and full name

$fields = \core_user\fields::for_name()->with_userpic()->get_required_fields();

If you need both types of fields, you can combine them by creating the object initially with a 'for' method, and then calling the 'with' method to add a different category of fields.

List fields required to display a user's identity

When displaying a table of users, the name is always included (and sometimes a picture), as above. Other 'identity fields' are configurable using the showuseridentity admin setting, and display only to users who have the permission to see them. For example, it could be configured so that email addresses are shown, or user names, or department, or a custom field. These fields usually display in separate table columns.

Because the capability for the current user depends on the location you are looking at, you need to pass a context when getting these fields.

$fields = \core_user\fields::for_identity($context)->get_required_fields();

The list of fields from this function might include custom profile fields e.g. 'profile_field_frog'. In legacy code which only supports fields on the user table, you can pass false to the second 'allow custom fields' parameter of the function:

$fields = \core_user\fields::for_identity($context, false)->get_required_fields();

Now it won't return any custom profile fields (and your code doesn't support them, which is sad).

Add or remove arbitrary extra fields

Sometimes you might want a list of fields to contain extra fields. You could just add them to the array, but that could cause duplicates in some situations which might result in bugs that only appear in certain settings. Instead, there is a convenient way to include them in these lists:

$fields = \core_user\fields::for_identity($context)->including('email')->get_required_fields();

Alternatively you might want to exclude a field - this would usually be because you know you are going to list that field in a database query separately. It is OK to exclude a field whether or not it is actually included; that way the code will continue to work whatever the field list.

$fields = \core_user\fields::for_name()->excluding('firstname')->get_required_fields();

You can use both including and excluding functions if you want.

Getting SQL

In most cases it is not very useful to just get a list of fields. You also need to create the SQL to obtain the values for the fields.

Let's use a simple example - we are writing code that displays a list of all users in the whole system ordered by their last access date, most recent first. For some reason we are also including deleted users (but maybe we're going to display them differently). Here is a basic SQL query that does this:

$result = $DB->get_records_sql("
        SELECT u.id, u.deleted
          FROM {user} u
      ORDER BY u.lastaccess DESC", [], 0, 10);

Suppose that we also want to include the user's name, and any identity fields that are enabled for the current user. We don't want to include the 'id' or 'deleted' field because they're already included in the query.

We can create a user fields object like this:

$context = \context_system::instance();
$userfields = \core_user\fields::for_name()->with_identity($context)->excluding('id', 'deleted');

The user fields object can create SQL snippets for you like this:

$sql = $userfields->get_sql('u');

This returns an object with the fields 'selects', 'joins', 'params', and (not normally needed) 'mappings'. Here is how you use it with the above SQL query:

$result = $DB->get_records_sql("
        SELECT u.id, u.deleted {$sql->selects}
          FROM {user} u
               {$sql->joins}
      ORDER BY u.lastaccess DESC", $sql->params, 0, 10);

There are many options to the get_sql function, as well as the user table alias shown. For example, you can:

  • Use named parameters instead of ? parameters.
  • Add a prefix (e.g.u_) to all field names in the result to ensure they don't clash with other fields in the query.
  • Rename the userid field e.g. to 'userid'.
  • Turn off the leading comma in the selects list.

This last one might need explaining. By default, the 'selects' list starts with a comma, which means you include it in the query as shown above (without a comma before it). By doing this, it will still work correctly if there are no fields to add (then it returns selects as blank, so there is no 'spare' comma).

Selective field lists

When you have created a user fields object that includes a lot of fields for different purposes, like the one in the above example, you might need to get a list of only some of those fields. The most common use case for this is when deciding on columns to display in a table. In the above example, we don't want a column in the table for every fields in the $userfields object - there doesn't need to be a column for the 'firstnamephonetic' field, for instance. But we do need to know the extra identity fields that are being included, because these should each have a column.

An extra parameter on get_required_fields lets you include only one category of fields from the object:

$extracolumns = $userfields->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);

Field names

To display those columns you will need a header with a field name. You can get a field name as follows:

$header = \core_user\fields::get_display_name($field);

This works for both standard user table fields e.g. email (it will get the appropriate language string), and for custom fields (it will get the name for the custom field).

Older Moodle versions

Prior to Moodle 3.11 the main functions used to carry out the same jobs were called get_extra_user_fields(), get_extra_user_fields_sql(), user_picture::fields(), and get_all_user_name_fields(). These all work, but are deprecated, in Moodle 3.11.