Issue #1479454 by Hugo Wetterberg, galooph, dawehner, andypost, marcingy, heyrocker...
[project/drupal.git] / core / modules / user / user.api.php
1 <?php
2
3 use Drupal\Core\Entity\EntityInterface;
4
5 /**
6 * @file
7 * Hooks provided by the User module.
8 */
9
10 /**
11 * @addtogroup hooks
12 * @{
13 */
14
15 /**
16 * Act on a newly created user.
17 *
18 * This hook runs after a new user object has just been instantiated. It can be
19 * used to set initial values, e.g. to provide defaults.
20 *
21 * @param \Drupal\user\Plugin\Core\Entity\User $user
22 * The user object.
23 */
24 function hook_user_create(\Drupal\user\Plugin\Core\Entity\User $user) {
25 if (!isset($user->foo)) {
26 $user->foo = 'some_initial_value';
27 }
28 }
29
30 /**
31 * Act on user objects when loaded from the database.
32 *
33 * Due to the static cache in user_load_multiple() you should not use this
34 * hook to modify the user properties returned by the {users} table itself
35 * since this may result in unreliable results when loading from cache.
36 *
37 * @param $users
38 * An array of user objects, indexed by uid.
39 *
40 * @see user_load_multiple()
41 * @see profile_user_load()
42 */
43 function hook_user_load($users) {
44 $result = db_query('SELECT uid, foo FROM {my_table} WHERE uid IN (:uids)', array(':uids' => array_keys($users)));
45 foreach ($result as $record) {
46 $users[$record->uid]->foo = $record->foo;
47 }
48 }
49
50 /**
51 * Act before user deletion.
52 *
53 * This hook is invoked from user_delete_multiple() before
54 * field_attach_delete() is called and before the user is actually removed from
55 * the database.
56 *
57 * Modules should additionally implement hook_user_cancel() to process stored
58 * user data for other account cancellation methods.
59 *
60 * @param $account
61 * The account that is about to be deleted.
62 *
63 * @see hook_user_delete()
64 * @see user_delete_multiple()
65 */
66 function hook_user_predelete($account) {
67 db_delete('mytable')
68 ->condition('uid', $account->uid)
69 ->execute();
70 }
71
72 /**
73 * Respond to user deletion.
74 *
75 * This hook is invoked from user_delete_multiple() after field_attach_delete()
76 * has been called and after the user has been removed from the database.
77 *
78 * Modules should additionally implement hook_user_cancel() to process stored
79 * user data for other account cancellation methods.
80 *
81 * @param $account
82 * The account that has been deleted.
83 *
84 * @see hook_user_predelete()
85 * @see user_delete_multiple()
86 */
87 function hook_user_delete($account) {
88 drupal_set_message(t('User: @name has been deleted.', array('@name' => $account->name)));
89 }
90
91 /**
92 * Act on user account cancellations.
93 *
94 * This hook is invoked from user_cancel() before a user account is canceled.
95 * Depending on the account cancellation method, the module should either do
96 * nothing, unpublish content, or anonymize content. See user_cancel_methods()
97 * for the list of default account cancellation methods provided by User module.
98 * Modules may add further methods via hook_user_cancel_methods_alter().
99 *
100 * This hook is NOT invoked for the 'user_cancel_delete' account cancellation
101 * method. To react to that method, implement hook_user_predelete() or
102 * hook_user_delete() instead.
103 *
104 * Expensive operations should be added to the global account cancellation batch
105 * by using batch_set().
106 *
107 * @param $edit
108 * The array of form values submitted by the user.
109 * @param $account
110 * The user object on which the operation is being performed.
111 * @param $method
112 * The account cancellation method.
113 *
114 * @see user_cancel_methods()
115 * @see hook_user_cancel_methods_alter()
116 */
117 function hook_user_cancel($edit, $account, $method) {
118 switch ($method) {
119 case 'user_cancel_block_unpublish':
120 // Unpublish nodes (current revisions).
121 module_load_include('inc', 'node', 'node.admin');
122 $nodes = db_select('node', 'n')
123 ->fields('n', array('nid'))
124 ->condition('uid', $account->uid)
125 ->execute()
126 ->fetchCol();
127 node_mass_update($nodes, array('status' => 0));
128 break;
129
130 case 'user_cancel_reassign':
131 // Anonymize nodes (current revisions).
132 module_load_include('inc', 'node', 'node.admin');
133 $nodes = db_select('node', 'n')
134 ->fields('n', array('nid'))
135 ->condition('uid', $account->uid)
136 ->execute()
137 ->fetchCol();
138 node_mass_update($nodes, array('uid' => 0));
139 // Anonymize old revisions.
140 db_update('node_revision')
141 ->fields(array('uid' => 0))
142 ->condition('uid', $account->uid)
143 ->execute();
144 break;
145 }
146 }
147
148 /**
149 * Modify account cancellation methods.
150 *
151 * By implementing this hook, modules are able to add, customize, or remove
152 * account cancellation methods. All defined methods are turned into radio
153 * button form elements by user_cancel_methods() after this hook is invoked.
154 * The following properties can be defined for each method:
155 * - title: The radio button's title.
156 * - description: (optional) A description to display on the confirmation form
157 * if the user is not allowed to select the account cancellation method. The
158 * description is NOT used for the radio button, but instead should provide
159 * additional explanation to the user seeking to cancel their account.
160 * - access: (optional) A boolean value indicating whether the user can access
161 * a method. If 'access' is defined, the method cannot be configured as
162 * default method.
163 *
164 * @param $methods
165 * An array containing user account cancellation methods, keyed by method id.
166 *
167 * @see user_cancel_methods()
168 * @see user_cancel_confirm_form()
169 */
170 function hook_user_cancel_methods_alter(&$methods) {
171 // Limit access to disable account and unpublish content method.
172 $methods['user_cancel_block_unpublish']['access'] = user_access('administer site configuration');
173
174 // Remove the content re-assigning method.
175 unset($methods['user_cancel_reassign']);
176
177 // Add a custom zero-out method.
178 $methods['mymodule_zero_out'] = array(
179 'title' => t('Delete the account and remove all content.'),
180 'description' => t('All your content will be replaced by empty strings.'),
181 // access should be used for administrative methods only.
182 'access' => user_access('access zero-out account cancellation method'),
183 );
184 }
185
186 /**
187 * Alter the username that is displayed for a user.
188 *
189 * Called by user_format_name() to allow modules to alter the username that's
190 * displayed. Can be used to ensure user privacy in situations where
191 * $account->name is too revealing.
192 *
193 * @param $name
194 * The string that user_format_name() will return.
195 *
196 * @param $account
197 * The account object passed to user_format_name().
198 *
199 * @see user_format_name()
200 */
201 function hook_user_format_name_alter(&$name, $account) {
202 // Display the user's uid instead of name.
203 if (isset($account->uid)) {
204 $name = t('User !uid', array('!uid' => $account->uid));
205 }
206 }
207
208 /**
209 * Add mass user operations.
210 *
211 * This hook enables modules to inject custom operations into the mass operations
212 * dropdown found at admin/people, by associating a callback function with
213 * the operation, which is called when the form is submitted. The callback function
214 * receives one initial argument, which is an array of the checked users.
215 *
216 * @return
217 * An array of operations. Each operation is an associative array that may
218 * contain the following key-value pairs:
219 * - "label": Required. The label for the operation, displayed in the dropdown menu.
220 * - "callback": Required. The function to call for the operation.
221 * - "callback arguments": Optional. An array of additional arguments to pass to
222 * the callback function.
223 *
224 */
225 function hook_user_operations() {
226 $operations = array(
227 'unblock' => array(
228 'label' => t('Unblock the selected users'),
229 'callback' => 'user_user_operations_unblock',
230 ),
231 'block' => array(
232 'label' => t('Block the selected users'),
233 'callback' => 'user_user_operations_block',
234 ),
235 'cancel' => array(
236 'label' => t('Cancel the selected user accounts'),
237 ),
238 );
239 return $operations;
240 }
241
242 /**
243 * Act on a user account being inserted or updated.
244 *
245 * This hook is invoked before the user account is saved to the database.
246 *
247 * @param $account
248 * The user account object.
249 *
250 * @see hook_user_insert()
251 * @see hook_user_update()
252 */
253 function hook_user_presave($account) {
254 // Ensure that our value is an array.
255 if (isset($account->mymodule_foo)) {
256 $account->mymodule_foo = (array) $account->mymodule_foo;
257 }
258 }
259
260 /**
261 * Respond to creation of a new user account.
262 *
263 * Note that when this hook is invoked, the changes have not yet been written to
264 * the database, because a database transaction is still in progress. The
265 * transaction is not finalized until the insert operation is entirely completed
266 * and \Drupal\user\DataStorageController::save() goes out of scope. You should
267 * not rely on data in the database at this time as it is not updated yet. You
268 * should also note that any write/update database queries executed from this hook
269 * are also not committed immediately. Check \Drupal\user\DataStorageController::save()
270 * and db_transaction() for more info.
271 *
272 * @param $account
273 * The user account object.
274 *
275 * @see hook_user_presave()
276 * @see hook_user_update()
277 */
278 function hook_user_insert($account) {
279 db_insert('user_changes')
280 ->fields(array(
281 'uid' => $account->uid,
282 'created' => time(),
283 ))
284 ->execute();
285 }
286
287 /**
288 * Respond to updates to a user account.
289 *
290 * Note that when this hook is invoked, the changes have not yet been written to
291 * the database, because a database transaction is still in progress. The
292 * transaction is not finalized until the update operation is entirely completed
293 * and \Drupal\user\DataStorageController::save() goes out of scope. You should not
294 * rely on data in the database at this time as it is not updated yet. You should
295 * also note that any write/update database queries executed from this hook are
296 * also not committed immediately. Check \Drupal\user\DataStorageController::save()
297 * and db_transaction() for more info.
298 *
299 * @param $account
300 * The user account object.
301 *
302 * @see hook_user_presave()
303 * @see hook_user_insert()
304 */
305 function hook_user_update($account) {
306 db_insert('user_changes')
307 ->fields(array(
308 'uid' => $account->uid,
309 'changed' => time(),
310 ))
311 ->execute();
312 }
313
314 /**
315 * The user just logged in.
316 *
317 * @param $account
318 * The user object on which the operation was just performed.
319 */
320 function hook_user_login($account) {
321 $config = config('system.timezone');
322 // If the user has a NULL time zone, notify them to set a time zone.
323 if (!$account->timezone && $config->get('user.configurable') && $config->get('user.warn')) {
324 drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
325 }
326 }
327
328 /**
329 * The user just logged out.
330 *
331 * @param $account
332 * The user object on which the operation was just performed.
333 */
334 function hook_user_logout($account) {
335 db_insert('logouts')
336 ->fields(array(
337 'uid' => $account->uid,
338 'time' => time(),
339 ))
340 ->execute();
341 }
342
343 /**
344 * The user's account information is being displayed.
345 *
346 * The module should format its custom additions for display and add them to the
347 * $account->content array.
348 *
349 * @param \Drupal\user\Plugin\Core\Entity\User $account
350 * The user object on which the operation is being performed.
351 * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
352 * The entity_display object holding the display options configured for the
353 * user components.
354 * @param $view_mode
355 * View mode, e.g. 'full'.
356 * @param $langcode
357 * The language code used for rendering.
358 *
359 * @see hook_user_view_alter()
360 * @see hook_entity_view()
361 */
362 function hook_user_view(\Drupal\user\Plugin\Core\Entity\User $account, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) {
363 // Only do the extra work if the component is configured to be displayed.
364 // This assumes a 'mymodule_addition' extra field has been defined for the
365 // user entity type in hook_field_extra_fields().
366 if ($display->getComponent('mymodule_addition')) {
367 $account->content['mymodule_addition'] = array(
368 '#markup' => mymodule_addition($account),
369 '#theme' => 'mymodule_my_additional_field',
370 );
371 }
372 }
373
374 /**
375 * The user was built; the module may modify the structured content.
376 *
377 * This hook is called after the content has been assembled in a structured array
378 * and may be used for doing processing which requires that the complete user
379 * content structure has been built.
380 *
381 * If the module wishes to act on the rendered HTML of the user rather than the
382 * structured content array, it may use this hook to add a #post_render callback.
383 * Alternatively, it could also implement hook_preprocess_HOOK() for
384 * user.tpl.php. See drupal_render() and theme() documentation
385 * respectively for details.
386 *
387 * @param $build
388 * A renderable array representing the user.
389 * @param \Drupal\user\Plugin\Core\Entity\User $account
390 * The user account being rendered.
391 * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
392 * The entity_display object holding the display options configured for the
393 * user components.
394 *
395 * @see user_view()
396 * @see hook_entity_view_alter()
397 */
398 function hook_user_view_alter(&$build, \Drupal\user\Plugin\Core\Entity\User $account, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display) {
399 // Check for the existence of a field added by another module.
400 if (isset($build['an_additional_field'])) {
401 // Change its weight.
402 $build['an_additional_field']['#weight'] = -10;
403 }
404
405 // Add a #post_render callback to act on the rendered HTML of the user.
406 $build['#post_render'][] = 'my_module_user_post_render';
407 }
408
409 /**
410 * Inform other modules that a user role is about to be saved.
411 *
412 * Modules implementing this hook can act on the user role object before
413 * it has been saved to the database.
414 *
415 * @param $role
416 * A user role object.
417 *
418 * @see hook_user_role_insert()
419 * @see hook_user_role_update()
420 */
421 function hook_user_role_presave($role) {
422 // Set a UUID for the user role if it doesn't already exist
423 if (empty($role->uuid)) {
424 $role->uuid = uuid_uuid();
425 }
426 }
427
428 /**
429 * Inform other modules that a user role has been added.
430 *
431 * Modules implementing this hook can act on the user role object when saved to
432 * the database. It's recommended that you implement this hook if your module
433 * adds additional data to user roles object. The module should save its custom
434 * additions to the database.
435 *
436 * @param $role
437 * A user role object.
438 */
439 function hook_user_role_insert($role) {
440 // Save extra fields provided by the module to user roles.
441 db_insert('my_module_table')
442 ->fields(array(
443 'rid' => $role->id(),
444 'role_description' => $role->description,
445 ))
446 ->execute();
447 }
448
449 /**
450 * Inform other modules that a user role has been updated.
451 *
452 * Modules implementing this hook can act on the user role object when updated.
453 * It's recommended that you implement this hook if your module adds additional
454 * data to user roles object. The module should save its custom additions to
455 * the database.
456 *
457 * @param $role
458 * A user role object.
459 */
460 function hook_user_role_update($role) {
461 // Save extra fields provided by the module to user roles.
462 db_merge('my_module_table')
463 ->key(array('rid' => $role->id()))
464 ->fields(array(
465 'role_description' => $role->description
466 ))
467 ->execute();
468 }
469
470 /**
471 * Inform other modules that a user role has been deleted.
472 *
473 * This hook allows you act when a user role has been deleted.
474 * If your module stores references to roles, it's recommended that you
475 * implement this hook and delete existing instances of the deleted role
476 * in your module database tables.
477 *
478 * @param $role
479 * The $role object being deleted.
480 */
481 function hook_user_role_delete($role) {
482 // Delete existing instances of the deleted role.
483 db_delete('my_module_table')
484 ->condition('rid', $role->id())
485 ->execute();
486 }
487
488 /**
489 * @} End of "addtogroup hooks".
490 */